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-04-30 09:28:55 +00:00
this . clear ( ) ;
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 ) {
2020-04-30 09:28:55 +00:00
/* "/{ressourceName}/{ressourceId}/..." -> ["{ressourceId}", "..."] */
pathArray = operation . path . split ( "/" ) . slice ( 2 ) ;
2020-01-29 09:50:31 +00:00
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" :
2020-04-16 11:28:09 +00:00
item . values ( { status : operation . value ,
"analyse-link" : [ "analysing" , "prepared" , "start analysis" ] . includes ( operation . value ) ? ` /corpora/ ${ pathArray [ 0 ] } /analyse ` : "" } ) ;
2020-01-29 09:50:31 +00:00
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-04-15 08:32:21 +00:00
"analyse-link" : [ "analysing" , "prepared" , "start analysis" ] . includes ( corpus . status ) ? ` /corpora/ ${ corpus . id } /analyse ` : "" ,
2020-02-12 11:19:54 +00:00
"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 >
2020-04-08 09:37:34 +00:00
< span class = "badge new status" data - badge - caption = "" >
< / s p a n >
2020-02-12 11:19:54 +00:00
< / t d >
< td class = "right-align" >
2020-06-25 15:44:55 +00:00
< a class = "btn-floating edit-link waves-effect waves-light" >
2020-04-08 09:37:34 +00:00
< i class = "material-icons" > edit < / i >
< / a >
2020-06-25 15:44:55 +00:00
< a class = "btn-floating analyse-link waves-effect waves-light" >
< i class = "material-icons right" > search < / i >
2020-04-08 09:37:34 +00:00
< / a >
2020-02-12 11:19:54 +00:00
< / 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" >
2020-06-25 15:44:55 +00:00
< a class = "btn-floating link waves-effect waves-light" >
< i class = "material-icons right" > send < / i >
2020-04-08 09:37:34 +00:00
< / a >
2020-02-12 11:19:54 +00:00
< / 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-04-09 12:49:17 +00:00
constructor ( idOrElement , options = { } ) {
2020-04-14 09:31:57 +00:00
super ( idOrElement , options ) ;
2020-04-23 10:07:08 +00:00
this . eventTokens = { } ; // all span tokens which are holdeing events if expert
// mode is on. Collected here to delete later on
this . currentExpertTokenElements = { } ; // all token elements which have added
// classes like chip and hoverable for expert view. Collected
//here to delete later on
2020-06-26 07:51:10 +00:00
this . addToSubResultsStatus = { } ; // holds True/false for check buttons used to add matches tu sub-results. If checked, it is True. If unchecked, it is false. Buttons for this have the class add. Those little round check buttons.
this . addToSubResultsIdsToShow = new Set ( ) ; // If check button is pressed its corresponding data_index is saved in this set. The set is shown to the user.
2020-04-09 12:49:17 +00:00
}
2020-01-29 15:12:57 +00:00
2020-06-19 10:30:05 +00:00
// handels interactionElements during a pagination navigation
2020-06-26 07:51:10 +00:00
// loops over interactionElements and executes callback functions accordingly
2020-06-19 10:30:05 +00:00
pageChangeEventInteractionHandler ( interactionElements ) {
// get elements to check thier status
for ( let interaction of interactionElements ) {
2020-06-19 13:49:11 +00:00
if ( interaction . checkStatus ) {
2020-06-25 15:44:55 +00:00
if ( interaction . element . checked ) {
2020-06-19 13:49:11 +00:00
let f _on = interaction . bindThisToCallback ( "on" ) ;
let args _on = interaction . callbacks . on . args ;
f _on ( ... args _on ) ;
} else {
let f _off = interaction . bindThisToCallback ( "off" ) ;
let args _off = interaction . callbacks . off . args ;
f _off ( ... args _off ) ;
}
2020-06-19 10:30:05 +00:00
} else {
2020-06-19 13:49:11 +00:00
let f = interaction . bindThisToCallback ( "noCheck" ) ;
let args = interaction . callbacks . noCheck . args ;
f ( ... args ) ;
2020-06-19 10:30:05 +00:00
}
}
}
2020-04-14 09:31: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 ) ;
2020-04-08 09:37:34 +00:00
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" )
} ;
2020-04-07 11:13:48 +00:00
return displayOptionsData
}
2020-06-25 08:51:51 +00:00
// ###### Functions to add one match to a sub-results ######
2020-06-26 07:51:10 +00:00
// activate the add buttons
2020-06-25 08:51:51 +00:00
activateAddToSubResults ( ) {
subResultsIdListElement . classList . remove ( "hide" ) ;
subResultsCreateElement . classList . remove ( "hide" ) ;
let addToSubResultsBtnElements = document . getElementsByClassName ( "add" ) ;
for ( let addToSubResultsBtn of addToSubResultsBtnElements ) {
addToSubResultsBtn . classList . remove ( "hide" ) ;
2020-06-19 10:30:05 +00:00
}
}
2020-06-26 07:51:10 +00:00
// deactivate the add buttons
2020-06-25 08:51:51 +00:00
deactivateAddToSubResults ( ) {
subResultsIdListElement . classList . add ( "hide" ) ;
subResultsCreateElement . classList . add ( "hide" ) ;
let addToSubResultsBtnElements = document . getElementsByClassName ( "add" ) ;
for ( let addToSubResultsBtn of addToSubResultsBtnElements ) {
addToSubResultsBtn . classList . add ( "hide" ) ;
2020-06-19 10:30:05 +00:00
}
}
2020-06-25 15:44:55 +00:00
2020-06-26 07:51:10 +00:00
// Used in addToSubResults and inspect to toggle the design of the check
// buttons according to its checked unchecked status.
2020-06-25 15:44:55 +00:00
helperActivateBtn ( btn ) {
btn . classList . remove ( "grey" ) ;
btn . classList . add ( "green" ) ;
btn . innerText = "check" ;
}
2020-06-26 07:51:10 +00:00
// Used in addToSubResults and inspect to toggle the design of the check
// buttons according to its checked unchecked status.
2020-06-25 15:44:55 +00:00
helperDeactivateBtn ( btn ) {
btn . classList . remove ( "green" ) ;
btn . classList . add ( "grey" ) ;
btn . innerText = "add" ;
}
2020-06-26 07:51:10 +00:00
// Either adds or removes a match to the sub-results. For this it checks
// onclick if the current button has been checked or not. For this the
// function checks if its status in addToSubResultsStatus is either flase or
// true. Adds match to sub-results if status is false if status is true it
// removes it.
2020-06-25 15:44:55 +00:00
addToSubResults ( dataIndex , tableCall = true ) {
2020-06-26 07:51:10 +00:00
let textarea = subResultsIdListElement . getElementsByTagName ( "textarea" ) [ 0 ] ;
2020-06-25 08:51:51 +00:00
if ( ! this . addToSubResultsStatus [ dataIndex ]
|| this . addToSubResultsStatus === undefined ) {
2020-06-26 07:51:10 +00:00
// add button is activated because status is either false or undefined
2020-06-25 15:44:55 +00:00
this . helperActivateBtn ( event . target ) ;
2020-06-26 07:51:10 +00:00
this . addToSubResultsStatus [ dataIndex ] = true ; // sets status to true
this . addToSubResultsIdsToShow . add ( dataIndex + 1 ) ; // + 1 because user does not see zero indexd data indexes
textarea . innerText = [ ... this . addToSubResultsIdsToShow ] . sort ( function ( a , b ) { return a - b } ) . join ( ", " ) ; // automaticalle sorts ids into the textarea in ascending order
M . textareaAutoResize ( textarea ) ; // after an insert textarea has to be resized manually
2020-06-29 09:09:12 +00:00
nrMarkedMatches . innerText = [ ... this . addToSubResultsIdsToShow ] . length ;
2020-06-25 08:51:51 +00:00
} else if ( this . addToSubResultsStatus [ dataIndex ] ) {
2020-06-26 07:51:10 +00:00
// add button is deactivated because status is true
2020-06-25 15:44:55 +00:00
this . helperDeactivateBtn ( event . target ) ;
2020-06-26 07:51:10 +00:00
this . addToSubResultsStatus [ dataIndex ] = false ; // sets status to false
this . addToSubResultsIdsToShow . delete ( dataIndex + 1 ) ; // + 1 because user does not see zero indexd data indexes
textarea . innerText = [ ... this . addToSubResultsIdsToShow ] . sort ( function ( a , b ) { return a - b } ) . join ( ", " ) ; // automaticalle sorts ids into the textarea in ascending order
2020-06-29 09:09:12 +00:00
nrMarkedMatches . innerText = [ ... this . addToSubResultsIdsToShow ] . length ;
2020-06-26 07:51:10 +00:00
M . textareaAutoResize ( textarea ) ; // after an insert textarea has to be resized manually
2020-06-19 10:30:05 +00:00
}
2020-06-26 07:51:10 +00:00
// Toggles the create button accoring to the number of ids in addToSubResultsIdsToShow
2020-06-25 08:51:51 +00:00
if ( [ ... this . addToSubResultsIdsToShow ] . length > 0 ) {
subResultsCreateElement . firstElementChild . classList . remove ( "disabled" ) ;
} else if ( [ ... this . addToSubResultsIdsToShow ] . length === 0 ) {
subResultsCreateElement . firstElementChild . classList . add ( "disabled" ) ;
}
2020-06-26 07:51:10 +00:00
// After a match as been added or removed the export button will be
// disabled because the sub-results have been alterd and have to be built //// again.
2020-06-25 08:51:51 +00:00
subResultsExportElement . classList . add ( "disabled" ) ;
2020-06-26 07:51:10 +00:00
// Also activate/deactivate buttons in the table/jsList results accordingly
//if button in inspect was activated/deactivated.
// This part only runs if tableCall is false.
2020-06-25 15:44:55 +00:00
if ( ! tableCall ) {
2020-06-26 07:51:10 +00:00
let tableAddBtn = document . getElementById ( "query-results" ) . querySelectorAll ( ` [data-index=" ${ dataIndex } "] ` ) [ 0 ] . getElementsByClassName ( 'add' ) [ 0 ] . firstElementChild ; // gets the add button from the list view
2020-06-25 15:44:55 +00:00
if ( this . addToSubResultsStatus [ dataIndex ] ) {
this . helperActivateBtn ( tableAddBtn ) ;
} else {
this . helperDeactivateBtn ( tableAddBtn ) ;
}
}
2020-06-19 10:30:05 +00:00
}
2020-06-26 07:51:10 +00:00
// Triggers emit to get full match context from server for a number of
// matches identified by their data_index.
2020-06-25 08:51:51 +00:00
getMatchWithContext ( dataIndexes , type ) {
let tmp _first _cpos = [ ] ;
let tmp _last _cpos = [ ] ;
for ( let dataIndex of dataIndexes ) {
tmp _first _cpos . push ( results . data . matches [ dataIndex ] . c [ 0 ] ) ;
tmp _last _cpos . push ( results . data . matches [ dataIndex ] . c [ 1 ] ) ;
}
2020-06-19 13:49:11 +00:00
nopaque . socket . emit ( "corpus_analysis_inspect_match" ,
{
type : type ,
2020-06-25 08:51:51 +00:00
data _indexes : dataIndexes ,
first _cpos : tmp _first _cpos ,
last _cpos : tmp _last _cpos ,
2020-06-19 13:49:11 +00:00
}
) ;
}
2020-04-07 11:13:48 +00:00
// ###### Functions to inspect one match, to show more details ######
2020-04-08 09:37:34 +00:00
// activate inspect buttons if progress is 100
activateInspect ( ) {
2020-04-07 11:13:48 +00:00
if ( progress === 100 ) {
2020-06-19 13:49:11 +00:00
let inspectBtnElements ;
2020-04-07 11:13:48 +00:00
inspectBtnElements = document . getElementsByClassName ( "inspect" ) ;
for ( let inspectBtn of inspectBtnElements ) {
inspectBtn . classList . remove ( "disabled" ) ;
}
} else {
return
}
}
2020-06-25 08:51:51 +00:00
// gets result cpos infos for one dataIndex (list of length 1) to send back to
// the server
2020-06-19 10:30:05 +00:00
inspect ( dataIndex , type ) {
2020-06-29 09:09:12 +00:00
let contextMatchNrElement ;
2020-06-26 07:51:10 +00:00
// get result infos from server and show them in context modal
2020-06-25 08:51:51 +00:00
this . contextId = dataIndex [ 0 ] ;
2020-06-29 09:09:12 +00:00
// match nr for user to display derived from data_index
contextMatchNrElement = document . getElementById ( "context-match-nr" ) ;
contextMatchNrElement . innerText = this . contextId + 1 ;
2020-06-25 08:51:51 +00:00
let contextResultsElement ;
contextResultsElement = document . getElementById ( "context-results" ) ;
contextResultsElement . innerHTML = "" ; // clear it from old inspects
2020-06-19 13:49:11 +00:00
this . getMatchWithContext ( dataIndex , type ) ;
2020-04-07 11:13:48 +00:00
contextModal . open ( ) ;
2020-06-26 07:51:10 +00:00
// add a button to add this match to sub results with onclick event
2020-06-25 08:51:51 +00:00
let classes = ` btn-floating btn waves-effect ` +
` waves-light grey right `
2020-06-25 15:44:55 +00:00
let addToSubResultsIdsBtn = document . createElement ( "a" ) ;
addToSubResultsIdsBtn . setAttribute ( "class" , classes + ` add ` ) ;
addToSubResultsIdsBtn . innerHTML = '<i class="material-icons">add</i>' ;
2020-06-26 07:51:10 +00:00
addToSubResultsIdsBtn . onclick = ( ) => { this . addToSubResults ( dataIndex [ 0 ] , false ) } ;
// checks if a button has already been added to the inspect modal and removes it
2020-06-25 15:44:55 +00:00
if ( addToSubResultsFromInspectElement . children . length > 0 ) {
addToSubResultsFromInspectElement . firstElementChild . remove ( ) ;
}
2020-06-26 07:51:10 +00:00
// Changes the design of the add button according to its checked status
// upon opening the inspect modal.
2020-06-25 15:44:55 +00:00
if ( this . addToSubResultsStatus [ dataIndex [ 0 ] ] ) {
2020-06-26 07:51:10 +00:00
this . helperActivateBtn ( addToSubResultsIdsBtn . firstElementChild ) ;
2020-06-25 15:44:55 +00:00
} else if ( ! this . addToSubResultsStatus [ dataIndex [ 0 ] ] ) {
2020-06-26 07:51:10 +00:00
this . helperDeactivateBtn ( addToSubResultsIdsBtn . firstElementChild ) ;
2020-06-25 15:44:55 +00:00
}
addToSubResultsFromInspectElement . appendChild ( addToSubResultsIdsBtn ) ;
2020-04-07 11:13:48 +00:00
}
2020-06-19 10:30:05 +00:00
// create Element from HTML String helper function
2020-04-15 13:11:25 +00:00
HTMLTStrToElement ( htmlStr ) {
2020-04-15 12:55:29 +00:00
// https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518
let template = document . createElement ( "template" ) ;
htmlStr = htmlStr . trim ( ) ;
template . innerHTML = htmlStr ;
return template . content . firstChild ;
}
2020-06-26 07:51:10 +00:00
// Used as a callback to handle incoming match context results when inspect
// has been used.
2020-04-07 11:13:48 +00:00
showMatchContext ( response ) {
2020-04-15 12:55:29 +00:00
this . contextData ;
2020-04-08 09:37:34 +00:00
let c ;
2020-04-07 11:13:48 +00:00
let contextModalLoading ;
let contextModalReady ;
2020-04-08 09:37:34 +00:00
let contextResultsElement ;
2020-04-16 13:06:03 +00:00
let highlightSentencesSwitchElement ;
2020-04-20 11:48:40 +00:00
let htmlTokenStr ;
2020-04-08 09:37:34 +00:00
let lc ;
2020-04-20 11:48:40 +00:00
let modalExpertModeSwitchElement ;
2020-04-15 12:55:29 +00:00
let modalTokenElements ;
2020-04-20 11:48:40 +00:00
let nrOfContextSentences ;
2020-04-08 09:37:34 +00:00
let partElement ;
let rc ;
2020-04-07 11:13:48 +00:00
let token ;
2020-04-15 12:55:29 +00:00
let tokenHTMLArray ;
let tokenHTMlElement ;
2020-05-04 09:05:17 +00:00
let uniqueContextS ;
2020-04-20 11:48:40 +00:00
let uniqueS ;
2020-04-15 12:55:29 +00:00
this . contextData = response . payload ;
2020-06-29 09:09:12 +00:00
console . log ( this . contextData ) ;
2020-06-25 08:51:51 +00:00
this . contextData [ "cpos_ranges" ] = response . payload . cpos _ranges ;
2020-04-30 13:21:55 +00:00
this . contextData [ "query" ] = results . data . query ;
2020-05-04 09:05:17 +00:00
this . contextData [ "context_id" ] = this . contextId ;
2020-06-16 12:05:58 +00:00
this . contextData [ "match_count" ] = this . contextData . matches . length
2020-06-25 08:51:51 +00:00
this . contextData [ "corpus_type" ] = "inspect-result"
2020-04-30 13:21:55 +00:00
Object . assign ( this . contextData , results . metaData ) ;
2020-04-07 11:13:48 +00:00
contextResultsElement = document . getElementById ( "context-results" ) ;
2020-04-20 11:48:40 +00:00
modalExpertModeSwitchElement = document . getElementById ( "inspect-display-options-form-expert_mode_inspect" ) ;
highlightSentencesSwitchElement = document . getElementById ( "inspect-display-options-form-highlight_sentences" ) ;
nrOfContextSentences = document . getElementById ( "context-sentences" ) ;
2020-04-15 12:55:29 +00:00
uniqueS = new Set ( ) ;
2020-05-04 09:05:17 +00:00
uniqueContextS = new Set ( ) ;
2020-04-08 09:37:34 +00:00
// check if cpos ranges are used or not
2020-04-15 12:55:29 +00:00
if ( this . contextData . cpos _ranges == true ) {
2020-04-08 09:37:34 +00:00
// python range like function from MDN
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Sequence_generator_(range)
2020-04-07 11:13:48 +00:00
const range = ( start , stop , step ) => Array . from ( { length : ( stop - start ) / step + 1 } , ( _ , i ) => start + ( i * step ) ) ;
2020-06-16 12:05:58 +00:00
lc = range ( this . contextData . matches [ 0 ] . lc [ 0 ] , this . contextData . matches [ 0 ] . lc [ 1 ] , 1 )
c = range ( this . contextData . matches [ 0 ] . c [ 0 ] , this . contextData . matches [ 0 ] . c [ 1 ] , 1 )
rc = range ( this . contextData . matches [ 0 ] . rc [ 0 ] , this . contextData . matches [ 0 ] . rc [ 1 ] , 1 )
2020-04-07 11:13:48 +00:00
} else {
2020-06-16 12:05:58 +00:00
lc = this . contextData . matches [ 0 ] . lc ;
c = this . contextData . matches [ 0 ] . c ;
rc = this . contextData . matches [ 0 ] . rc ;
2020-04-07 11:13:48 +00:00
}
2020-04-08 09:37:34 +00:00
// create sentence strings as tokens
2020-04-15 12:55:29 +00:00
tokenHTMLArray = [ ] ;
2020-04-07 11:13:48 +00:00
for ( let cpos of lc ) {
2020-04-15 12:55:29 +00:00
token = this . contextData . cpos _lookup [ cpos ] ;
uniqueS . add ( token . s )
htmlTokenStr = ` <span class="token" ` +
` data-sid=" ${ token . s } " ` +
` data-cpos=" ${ cpos } "> ` +
` ${ token . word } ` +
` </span> ` ;
2020-04-15 13:11:25 +00:00
tokenHTMlElement = this . HTMLTStrToElement ( htmlTokenStr )
2020-04-15 12:55:29 +00:00
tokenHTMLArray . push ( tokenHTMlElement ) ;
2020-04-07 11:13:48 +00:00
}
for ( let cpos of c ) {
2020-04-15 12:55:29 +00:00
token = this . contextData . cpos _lookup [ cpos ] ;
2020-05-04 09:05:17 +00:00
uniqueContextS . add ( token . s ) ;
uniqueS . add ( token . s ) ;
2020-04-15 12:55:29 +00:00
htmlTokenStr = ` <span class="token bold light-green" ` +
` data-sid=" ${ token . s } " ` +
` data-cpos=" ${ cpos } " ` +
` style="text-decoration-line: underline;"> ` +
` ${ token . word } ` +
` </span> ` ;
2020-04-15 13:11:25 +00:00
tokenHTMlElement = this . HTMLTStrToElement ( htmlTokenStr )
2020-04-15 12:55:29 +00:00
tokenHTMLArray . push ( tokenHTMlElement ) ;
2020-04-07 11:13:48 +00:00
}
2020-05-04 09:05:17 +00:00
this . contextData [ "context_s_ids" ] = Array . from ( uniqueContextS ) ;
2020-04-07 11:13:48 +00:00
for ( let cpos of rc ) {
2020-04-15 12:55:29 +00:00
token = this . contextData . cpos _lookup [ cpos ] ;
uniqueS . add ( token . s )
htmlTokenStr = ` <span class="token" ` +
` data-sid=" ${ token . s } " ` +
` data-cpos=" ${ cpos } "> ` +
` ${ token . word } ` +
` </span> ` ;
2020-04-15 13:11:25 +00:00
tokenHTMlElement = this . HTMLTStrToElement ( htmlTokenStr )
2020-04-15 12:55:29 +00:00
tokenHTMLArray . push ( tokenHTMlElement ) ;
}
for ( let sId of uniqueS ) {
2020-04-16 11:49:21 +00:00
let htmlSentence = ` <span class="sentence" data-sid=" ${ sId } "></span> ` ;
2020-04-15 13:11:25 +00:00
let sentenceElement = this . HTMLTStrToElement ( htmlSentence ) ;
2020-04-15 12:55:29 +00:00
for ( let tokenElement of tokenHTMLArray ) {
if ( tokenElement . dataset . sid == sId ) {
sentenceElement . appendChild ( tokenElement ) ;
2020-04-23 11:28:13 +00:00
sentenceElement . insertAdjacentHTML ( "beforeend" , ` ` ) ;
2020-04-15 12:55:29 +00:00
} else {
continue ;
}
}
2020-04-16 11:49:21 +00:00
contextResultsElement . appendChild ( sentenceElement ) ;
2020-04-07 11:13:48 +00:00
}
2020-04-15 12:55:29 +00:00
2020-04-20 11:48:40 +00:00
// add inspect display options events
modalExpertModeSwitchElement . onchange = ( event ) => {
2020-04-16 13:06:03 +00:00
if ( event . target . checked ) {
this . expertModeOn ( "context-results" ) ;
} else {
this . expertModeOff ( "context-results" )
}
2020-04-20 11:48:40 +00:00
} ;
2020-04-16 13:06:03 +00:00
2020-04-20 11:48:40 +00:00
highlightSentencesSwitchElement . onchange = ( event ) => {
2020-04-16 13:06:03 +00:00
if ( event . target . checked ) {
this . higlightContextSentences ( ) ;
} else {
this . unhighlightContextSentences ( ) ;
}
2020-04-20 11:48:40 +00:00
} ;
nrOfContextSentences . onchange = ( event ) => {
2020-04-23 10:10:36 +00:00
// console.log(event.target.value);
2020-04-20 11:48:40 +00:00
this . changeSentenceContext ( event . target . value ) ;
}
// checks on new modal opening if switches are checked
// if switches are checked functions are executed
if ( modalExpertModeSwitchElement . checked ) {
this . expertModeOn ( "context-results" ) ;
}
2020-04-16 13:06:03 +00:00
if ( highlightSentencesSwitchElement . checked ) {
this . higlightContextSentences ( ) ;
2020-04-07 11:13:48 +00:00
}
2020-04-20 11:48:40 +00:00
// checks the value of the number of sentences to show on modal opening
// sets context sentences accordingly
this . changeSentenceContext ( nrOfContextSentences . value )
2020-04-07 11:13:48 +00:00
}
2020-06-26 07:51:10 +00:00
// splits context text into sentences based on spacy sentence split
2020-04-16 13:06:03 +00:00
higlightContextSentences ( ) {
let sentences ;
sentences = document . getElementById ( "context-results" ) . getElementsByClassName ( "sentence" ) ;
for ( let s of sentences ) {
2020-04-20 11:48:40 +00:00
s . insertAdjacentHTML ( "beforeend" , ` <span><br><br></span> ` )
2020-04-16 13:06:03 +00:00
}
}
unhighlightContextSentences ( ) {
let sentences ;
2020-04-20 11:48:40 +00:00
let br ;
2020-04-16 13:06:03 +00:00
sentences = document . getElementById ( "context-results" ) . getElementsByClassName ( "sentence" ) ;
for ( let s of sentences ) {
2020-04-20 11:48:40 +00:00
br = s . lastChild ;
br . remove ( ) ;
2020-04-16 13:06:03 +00:00
}
}
2020-06-26 07:51:10 +00:00
// changes how many context sentences in inspect view are shown
2020-04-20 11:48:40 +00:00
changeSentenceContext ( sValue , maxSValue = 10 ) {
let array ;
let sentences ;
let toHideArray ;
let toShowArray ;
sValue = maxSValue - sValue ;
2020-04-23 10:10:36 +00:00
// console.log(sValue);
2020-04-20 11:48:40 +00:00
sentences = document . getElementById ( "context-results" ) . getElementsByClassName ( "sentence" ) ;
array = Array . from ( sentences ) ;
if ( sValue != 0 ) {
toHideArray = array . slice ( 0 , sValue ) . concat ( array . slice ( - ( sValue ) ) ) ;
toShowArray = array . slice ( sValue , 9 ) . concat ( array . slice ( 9 , - ( sValue ) ) )
} else {
toHideArray = [ ] ;
toShowArray = array ;
}
2020-04-23 10:10:36 +00:00
// console.log(array);
// console.log("#######");
// console.log(toHideArray);
2020-04-20 11:48:40 +00:00
for ( let s of toHideArray ) {
s . classList . add ( "hide" ) ;
}
for ( let s of toShowArray ) {
s . classList . remove ( "hide" ) ;
}
2020-04-15 12:55:29 +00:00
}
2020-04-07 11:13:48 +00:00
// ###### 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 {
2020-04-14 09:31:57 +00:00
// console.log(this);
this . page = event . target . value ;
this . update ( ) ;
2020-04-20 11:59:28 +00:00
this . activateInspect ( ) ;
2020-06-30 13:15:06 +00:00
this . pageChangeEventInteractionHandler ( interactionElements ) ;
2020-04-14 09:31:57 +00:00
if ( expertModeSwitchElement . checked ) {
2020-04-20 11:55:11 +00:00
this . expertModeOn ( "query-display" ) ; // page holds new result rows, so add new tooltips
2020-04-14 09:31:57 +00:00
}
2020-04-27 13:22:20 +00:00
nopaque . flash ( "Updated matches per page." , "corpus" )
2020-04-07 11:13:48 +00:00
} catch ( e ) {
2020-04-14 09:31:57 +00:00
// console.log(e);
// console.log("resultsList has no results right now.");
2020-04-07 11:13:48 +00:00
}
}
2020-04-08 09:37:34 +00:00
// Event function triggered on context select change
// also if pagination is clicked
2020-04-07 11:13:48 +00:00
changeContext ( event ) {
2020-04-08 09:37:34 +00:00
let array ;
2020-04-07 11:13:48 +00:00
let lc ;
2020-04-08 09:37:34 +00:00
let newContextValue ;
2020-04-07 11:13:48 +00:00
let rc ;
try {
if ( event . type === "change" ) {
2020-04-27 13:22:20 +00:00
nopaque . flash ( "Updated context per match!" , "corpus" ) ;
2020-04-07 11:13:48 +00:00
}
} catch ( e ) {
} finally {
newContextValue = document . getElementById ( "display-options-form-result_context" ) . value ;
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 ######
2020-04-14 09:31:57 +00:00
// function to create a tooltip for the current hovered token
tooltipEventCreate ( event ) {
// console.log("Create Tooltip on mouseover.");
2020-04-07 11:13:48 +00:00
let token ;
2020-04-30 13:21:55 +00:00
token = results . data . cpos _lookup [ event . target . dataset . cpos ] ;
2020-04-15 12:55:29 +00:00
if ( ! token ) {
token = this . contextData . cpos _lookup [ event . target . dataset . cpos ] ;
}
2020-04-09 12:49:17 +00:00
this . addToolTipToTokenElement ( event . target , token ) ;
}
2020-04-14 09:31:57 +00:00
// Function to destroy the current Tooltip for the current hovered tooltip
// on mouse leave
tooltipEventDestroy ( event ) {
// console.log("Tooltip destroy on leave.");
this . currentTooltipElement . destroy ( ) ;
}
2020-04-16 13:06:03 +00:00
expertModeOn ( htmlId ) {
2020-06-19 10:30:05 +00:00
// turn the expert mode on for all tokens in the DOM element identified by its htmlID
if ( ! Array . isArray ( this . currentExpertTokenElements [ htmlId ] ) ) {
this . currentExpertTokenElements [ htmlId ] = [ ] ;
}
this . currentExpertTokenElements [ htmlId ] . push ( ... document . getElementById ( htmlId ) . getElementsByClassName ( "token" ) ) ;
2020-04-14 09:31:57 +00:00
this . tooltipEventCreateBind = this . tooltipEventCreate . bind ( this ) ;
this . tooltipEventDestroyBind = this . tooltipEventDestroy . bind ( this ) ;
2020-04-20 11:48:40 +00:00
this . eventTokens [ htmlId ] = [ ] ;
2020-04-16 13:06:03 +00:00
for ( let tokenElement of this . currentExpertTokenElements [ htmlId ] ) {
2020-04-09 12:49:17 +00:00
tokenElement . classList . add ( "chip" , "hoverable" , "expert-view" ) ;
2020-04-14 09:31:57 +00:00
tokenElement . onmouseover = this . tooltipEventCreateBind ;
tokenElement . onmouseout = this . tooltipEventDestroyBind ;
2020-04-16 13:06:03 +00:00
this . eventTokens [ htmlId ] . push ( tokenElement ) ;
2020-04-07 11:13:48 +00:00
}
}
// fuction that creates Tooltip for one token and extracts the corresponding
// infos from the result JSON
addToolTipToTokenElement ( tokenElement , token ) {
2020-04-14 09:31:57 +00:00
this . currentTooltipElement ;
this . currentTooltipElement = M . Tooltip . init ( tokenElement ,
2020-04-08 09:37:34 +00:00
{ "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" >
2020-04-30 13:21:55 +00:00
Title : $ { results . data . text _lookup [ token . text ] . title }
2020-04-08 09:37:34 +00:00
< br >
2020-04-30 13:21:55 +00:00
Author : $ { results . data . text _lookup [ token . text ] . author }
2020-04-08 09:37:34 +00:00
< br >
2020-04-30 13:21:55 +00:00
Publishing year : $ { results . data . text _lookup [ token . text ] . publishing _year }
2020-04-08 09:37:34 +00:00
< / t d >
< / t r >
< / t a b l e > ` }
2020-04-14 09:31:57 +00:00
) ;
2020-04-07 11:13:48 +00:00
}
// function to remove extra informations and animations from tokens
2020-04-16 13:06:03 +00:00
expertModeOff ( htmlId ) {
2020-04-14 09:31:57 +00:00
// console.log("Expert mode is off.");
2020-06-19 10:30:05 +00:00
if ( ! Array . isArray ( this . currentExpertTokenElements [ htmlId ] ) ) {
this . currentExpertTokenElements [ htmlId ] = [ ] ;
}
if ( ! Array . isArray ( this . eventTokens [ htmlId ] ) ) {
this . eventTokens [ htmlId ] = [ ] ;
}
2020-04-16 13:06:03 +00:00
for ( let tokenElement of this . currentExpertTokenElements [ htmlId ] ) {
2020-04-09 12:49:17 +00:00
tokenElement . classList . remove ( "chip" , "hoverable" , "expert-view" ) ;
}
2020-04-16 13:06:03 +00:00
this . currentExpertTokenElements [ htmlId ] = [ ] ;
2020-04-20 11:48:40 +00:00
2020-04-16 13:06:03 +00:00
for ( let eventToken of this . eventTokens [ htmlId ] ) {
2020-04-14 09:31:57 +00:00
eventToken . onmouseover = "" ;
eventToken . onmouseout = "" ;
2020-04-07 11:13:48 +00:00
}
2020-04-16 13:06:03 +00:00
this . eventTokens [ htmlId ] = [ ] ;
2020-04-07 11:13:48 +00:00
}
2020-01-30 13:23:19 +00:00
createResultRowElement ( item , chunk ) {
2020-06-25 15:44:55 +00:00
let aCellElement ;
2020-06-25 08:51:51 +00:00
let addToSubResultsBtn ;
2020-04-08 09:37:34 +00:00
let c ;
let cCellElement ;
let cpos ;
let inspectBtn
let lc ;
let lcCellElement ;
let matchNrElement ;
let matchRowElement ;
let rc ;
let rcCellElement ;
let textTitles ;
let textTitlesCellElement ;
let token ;
let values ;
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 ) {
2020-04-08 09:37:34 +00:00
// python range like function from MDN
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Sequence_generator_(range)
2020-04-02 09:37:45 +00:00
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-04-09 08:17:04 +00:00
matchRowElement . setAttribute ( "data-index" , values . index )
2020-02-03 11:58:40 +00:00
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-04-08 09:37:34 +00:00
token = chunk . cpos _lookup [ cpos ] ;
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
2020-06-25 15:44:55 +00:00
// get infos for hit of match and set actions
2020-04-08 09:37:34 +00:00
textTitles = new Set ( ) ;
2020-06-25 15:44:55 +00:00
aCellElement = document . createElement ( "td" ) ;
aCellElement . classList . add ( "actions" ) ;
2020-04-08 09:37:34 +00:00
cCellElement = document . createElement ( "td" ) ;
cCellElement . classList . add ( "match-hit" ) ;
2020-02-03 11:58:40 +00:00
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-04-08 09:37:34 +00:00
matchRowElement . appendChild ( cCellElement ) ;
2020-06-25 15:44:55 +00:00
matchRowElement . appendChild ( aCellElement ) ;
2020-04-02 09:37:45 +00:00
for ( cpos of c ) {
2020-04-08 09:37:34 +00:00
token = chunk . cpos _lookup [ cpos ] ;
cCellElement . insertAdjacentHTML ( "beforeend" ,
` <span class="token" data-cpos=" ${ cpos } "> ${ token . word } </span> ` ) ;
2020-02-03 11:58:40 +00:00
// get text titles of every hit cpos token
2020-04-08 09:37:34 +00:00
textTitles . add ( chunk . text _lookup [ token . text ] . title ) ;
2020-02-03 11:58:40 +00:00
}
2020-06-19 10:30:05 +00:00
// add some interaction buttons
// # some btn css rules and classes
2020-06-25 15:44:55 +00:00
let css = ` margin-right: 5px; margin-bottom: 5px; `
2020-06-19 13:49:11 +00:00
let classes = ` btn-floating btn waves-effect ` +
2020-06-25 15:44:55 +00:00
` waves-light grey `
2020-06-19 10:30:05 +00:00
// # add button to trigger more context to every match td
inspectBtn = document . createElement ( "a" ) ;
2020-06-25 15:44:55 +00:00
inspectBtn . setAttribute ( "style" , css ) ;
2020-06-19 10:30:05 +00:00
inspectBtn . setAttribute ( "class" , classes + ` disabled inspect `
) ;
inspectBtn . innerHTML = '<i class="material-icons">search</i>' ;
2020-06-25 08:51:51 +00:00
inspectBtn . onclick = ( ) => { this . inspect ( [ values . index ] , "inspect" ) } ;
// # add btn to add matches to sub-results. hidden per default
addToSubResultsBtn = document . createElement ( "a" ) ;
2020-06-25 15:44:55 +00:00
addToSubResultsBtn . setAttribute ( "style" , css ) ;
2020-06-25 08:51:51 +00:00
addToSubResultsBtn . setAttribute ( "class" , classes + ` hide add `
2020-06-19 10:30:05 +00:00
) ;
2020-06-25 08:51:51 +00:00
addToSubResultsBtn . innerHTML = '<i class="material-icons">add</i>' ;
2020-06-25 15:44:55 +00:00
addToSubResultsBtn . onclick = ( event ) => { this . addToSubResults ( values . index ) }
aCellElement . appendChild ( inspectBtn ) ;
2020-06-26 11:13:18 +00:00
aCellElement . appendChild ( addToSubResultsBtn ) ;
2020-06-19 10:30:05 +00:00
// add text titles at front as first td of one row
2020-02-03 11:58:40 +00:00
textTitlesCellElement . innerText = [ ... textTitles ] . join ( ", " ) ;
matchRowElement . insertAdjacentHTML ( "afterbegin" , textTitlesCellElement . outerHTML ) ;
2020-04-08 09:37:34 +00:00
matchNrElement . innerText = values . index + 1 ;
2020-02-03 12:59:37 +00:00
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-04-09 08:17:04 +00:00
token = chunk . cpos _lookup [ cpos ] ;
2020-04-08 09:37:34 +00:00
rcCellElement . insertAdjacentHTML ( "beforeend" ,
` <span class="token" data-cpos=" ${ cpos } "> ${ token . word } </span> ` ) ;
2020-02-03 11:58:40 +00:00
}
2020-01-30 13:23:19 +00:00
return matchRowElement
2020-01-29 15:12:57 +00:00
}
}