diff --git a/app.py b/app.py index 97ef310..75fe344 100644 --- a/app.py +++ b/app.py @@ -568,7 +568,7 @@ def GET(self, name): alert=block_user, limit=limit, is_git_auth=is_git_auth,invalid=False, project=conf.myProject,template=None, - query_templates=None,knowledge_extractor=False) + query_templates=None,knowledge_extractor=set()) def POST(self, name): """ Submit a new record @@ -579,7 +579,6 @@ def POST(self, name): the record ID (a timestamp) """ - web.header("X-Forwarded-For", session['ip_address']) web.header("Content-Type","text/html; charset=utf-8") web.header('Access-Control-Allow-Origin', '*') web.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') @@ -597,18 +596,17 @@ def POST(self, name): u.log_output('SUBMIT INVALID FORM', session['logged_in'], session['username'],name) return render.record(record_form=f, pageID=name, user=user, alert=block_user, limit=limit, is_git_auth=is_git_auth,invalid=True, - project=conf.myProject,template=None,query_templates=None,knowledge_extractor=False) + project=conf.myProject,template=None, + query_templates=None,knowledge_extractor=set()) else: recordData = web.input() - print("inputData", recordData) - # load the template selected by the user if 'res_name' in recordData: if recordData.res_name != 'None': f = forms.get_form(recordData.res_name) query_templates = u.get_query_templates(recordData.res_name) - extractor = u.has_extractor(recordData.res_name) + extractor = u.has_extractor(recordData.res_name) return render.record(record_form=f, pageID=name, user=user, alert=block_user, limit=limit, is_git_auth=is_git_auth,invalid=False, project=conf.myProject,template=recordData.res_name, @@ -690,7 +688,8 @@ def GET(self, name): return render.modify(graphdata=data, pageID=recordID, record_form=f, user=session['username'],ids_dropdown=ids_dropdown, is_git_auth=is_git_auth,invalid=False, - project=conf.myProject,template=res_template,query_templates=query_templates,knowledge_extractor=extractor) + project=conf.myProject,template=res_template, + query_templates=query_templates,knowledge_extractor=extractor) else: session['logged_in'] = 'False' raise web.seeother(prefixLocal+'/') diff --git a/forms.py b/forms.py index 8d86672..25b5547 100644 --- a/forms.py +++ b/forms.py @@ -216,7 +216,8 @@ def get_form(json_form, from_dict=False, subtemplate=False): class_= classes, value=default, mandatory = mandatory, - subtemplate = resource_class), ) + get_form(field['import_subtemplate'], subtemplate=True) + subtemplate = resource_class, + subtemplateID = field['import_subtemplate']), ) + get_form(field['import_subtemplate'], subtemplate=True) if subtemplate: return params diff --git a/static/css/main.css b/static/css/main.css index 0d2925c..f2273ef 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -776,6 +776,10 @@ span[class^='tag Q']:hover { margin-left: 20px; } +input[type='checkbox'], +input[type='radio'] { + accent-color: rgb(100, 23, 180); +} input[type='text'], input[type='textarea'], @@ -2009,14 +2013,83 @@ button#showTemplates { font-size: 85%; } -.import_form { +.import-form { margin-left: 0px !important; margin-top: 0.7em; } + .imported_graphs { margin-top: 0.7em; } +.import-form + .block_field { + margin-top: 15px; + margin-left: 10px; +} + +.import-form + .block_field .btn { + max-width: 35%; + float: right; +} + +/* new Knowledge Extraction code */ + +.extraction-form-div { + width: 90%; + margin-left: 5%; + margin-right: 5%; +} + +.extraction-form-div:first-of-type { + color: rgb(100, 23, 180); + border-bottom: 1px solid rgb(100, 23, 180); + margin-top: 0.5em; +} + +.fa-times { + position: absolute; + right: 50px; + margin-top: 12px; + color: rgb(100, 23, 180); + font-size: 0.9em; +} + +.extraction-form-label:nth-child(2) { + margin-left: 3% !important; +} + +.extraction-form-label, .extraction-form-input { + width: 48% !important; + display: inline-block; +} + +.block_field input[type="text"].extraction-form-input:first-of-type { + margin-left: 0px !important; +} + +.block_field input[type="text"].extraction-form-input { + margin-left: 3% !important; + padding-top: 0.4em; +} + +.add-parameter { + display: block; + margin-left: 5%; + margin-bottom: 1.2em; + font-size: 0.8em; + color: rgb(100, 23, 180); + cursor: pointer; +} + +.extractor-comment { + width: 90%; + margin-left: 5%; + margin-bottom: 0px; + padding: 5px; + font-size: 0.9em; + border-bottom: 1px solid darkgray; +} + /* subtemplates */ .check_subtemplate { margin-left: 1em; @@ -2162,10 +2235,10 @@ input[subtemplate]+.fa-plus-circle { #lang-form { display: block; position: absolute; - background: #eae2f6; + background: #ECE0FD; width: 400px; padding: 20px; - border: solid 1px black; + border: solid 1px rgb(100, 23, 180); border-radius: 5px; z-index: 1023; } diff --git a/static/js/main.js b/static/js/main.js index 277b882..0e039a3 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -2,7 +2,7 @@ if (graph.length) {var in_graph = "FROM <"+graph+">"} else {var in_graph = ""} const wd_img = ' ' const geo_img = ''; -const viaf_img = ''; +const viaf_img = ''; const wikidataEndpoint = "https://query.wikidata.org/sparql" $(document).ready(function() { @@ -2256,114 +2256,108 @@ function replace_existing_subforms() { } // create subrecords -function create_subrecord(resource_class, field_name, el, subform_id=null ) { +function create_subrecord(resourceClass, fieldName, el, subformId=null ) { // prepare a new subrecord id - if (!subform_id) { + if (!subformId) { var now = new Date().valueOf(); - subform_id = (now / 1000).toString().replace('.', '-'); + subformId = (now / 1000).toString().replace('.', '-'); } - var form_id = $('.corners').eq(0).find('form').eq(0).attr('id'); // either 'recordForm' or 'modifyForm' + var formId = $('.corners').eq(0).find('form').eq(0).attr('id'); // either 'recordForm' or 'modifyForm' replace_existing_subforms(); // prepare the new subrecord form - const subrecord_section = $("
"); - const subrecord_form = $("
"); - subrecord_form.append($("

"+field_name+"

")); + const subrecordSection = $("
"); + const subrecordForm = $("
"); + subrecordForm.append($("

"+fieldName+"

")); // create a clone for each input belonging to the requested (sub-)template - $("[class~='("+resource_class+")'][class~='original_subtemplate']").each(function() { + $("[class~='("+resourceClass+")'][class~='original_subtemplate']").each(function() { // CREATE A CLONE ELEMENT - const clone_element = $(this).parent().parent().clone(); - clone_element.attr("style", "display: block"); // make it visible - clone_element.find('input').attr('data-subform',subform_id); // associate the input field with the subrecord id - clone_element.find('input').removeClass('original_subtemplate'); + const cloneElement = $(this).parent().parent().clone(); + cloneElement.attr("style", "display: block"); // make it visible + cloneElement.find('input').attr('data-subform',subformId); // associate the input field with the subrecord id + cloneElement.find('input').removeClass('original_subtemplate'); // associate proper identifiers to input fields belonging to the subrecord form - var input_id = clone_element.find('input:not([type="hidden"])').attr('id'); - console.log(input_id) - clone_element.find('input:not([type="hidden"])').attr('id', input_id+"_"+subform_id.toString()); - clone_element.find('input:not([type="hidden"])').attr('name', input_id+"_"+subform_id.toString()); + var inputId = cloneElement.find('input:not([type="hidden"])').attr('id'); + cloneElement.find('input:not([type="hidden"])').attr('id', inputId+"_"+subformId.toString()); + cloneElement.find('input:not([type="hidden"])').attr('name', inputId+"_"+subformId.toString()); // SET LITERAL INPUT FIELDS - if (clone_element.find('[lang]').length>0) { - var literal_input = clone_element.find('[lang]'); - var language_list_section = literal_input.parent().prev(); - language_list_section.find('a').each(function() { - var onclick_attr = $(this).attr('onclick'); + if (cloneElement.find('[lang]').length>0) { + var literalInput = cloneElement.find('[lang]'); + var languageListSection = literalInput.parent().prev(); + languageListSection.find('a').each(function() { + var onclickAttr = $(this).attr('onclick'); var regex = /'([^"]*)'/g; - var original_id_extended = onclick_attr.match(regex)[0]; - var original_id = original_id_extended.substring(1, original_id_extended.length-1) - $(this).attr('onclick', onclick_attr.replace(original_id, original_id+'_'+subform_id)); + var originalIdExtended = onclickAttr.match(regex)[0]; + var originalId = originalIdExtended.substring(1, originalIdExtended.length-1) + $(this).attr('onclick', onclickAttr.replace(originalId, originalId+'_'+subformId)); }); } // add a main-lang hidden input in case of primary key - if (clone_element.find('input.disambiguate').next('[type="hidden"]').length > 0) { - var primary_key_lang_id = clone_element.find('input.disambiguate').next('[type="hidden"]').attr('id'); - clone_element.find('input[type="hidden"]').attr('id', primary_key_lang_id+"_"+subform_id.toString()); - clone_element.find('input[type="hidden"]').attr('name', primary_key_lang_id+"_"+subform_id.toString()); + if (cloneElement.find('input.disambiguate').next('[type="hidden"]').length > 0) { + var primaryKeyLangId = cloneElement.find('input.disambiguate').next('[type="hidden"]').attr('id'); + cloneElement.find('input[type="hidden"]').attr('id', primaryKeyLangId+"_"+subformId.toString()); + cloneElement.find('input[type="hidden"]').attr('name', primaryKeyLangId+"_"+subformId.toString()); } // SET SUBTEMPLATE FIELDS '+' BUTTON - clone_element.find('[subtemplate]').each(function(){ - var subtemplate_class = $(this).attr('subtemplate'); - var field_name = $(this).parent().prev().text(); - var add_subrecord_btn = $(this).next('i'); - add_subrecord_btn.on('click', function(){ - create_subrecord(subtemplate_class,field_name,add_subrecord_btn); + cloneElement.find('[subtemplate]').each(function(){ + var subtemplateClass = $(this).attr('subtemplate'); + var fieldName = $(this).parent().prev().text(); + var addSubrecordBtn = $(this).next('i'); + addSubrecordBtn.on('click', function(){ + create_subrecord(subtemplateClass,fieldName,addSubrecordBtn); }) }) - console.log($('[name="'+input_id+'_'+subform_id+'-subrecords"]')) - // retrieve previously provided values in case they are available (i.e., modify subrecords): - let clone_element_values = []; - // a) single value - if ($('#'+form_id+' #'+input_id+"_"+subform_id).length >0) { - const to_be_modified = $('#'+form_id+' #'+input_id+'_'+subform_id); - clone_element.find('input').val(to_be_modified.val()); + let clonedElementValues = []; + // a) single value fields + if ($('#'+formId+' #'+inputId+"_"+subformId).length >0) { + const toBeModified = $('#'+form_id+' #'+inputId+'_'+subformId); + cloneElement.find('input').val(toBeModified.val()); } - // b) multiple values - if ($('#'+form_id+' [name^="'+input_id+'_"][name$="_'+subform_id+'"]:not([name="'+input_id.split('_')[0]+'_'+subform_id+'"])').length >0) { - var imported_values = $('#'+form_id+' [name^="'+input_id.split('_')[0]+'_"][name$="_'+subform_id+'"]:not([name="'+input_id.split('_')[0]+'_'+subform_id+'"])'); - clone_element.find('.label div a').remove(); - if ($('#'+input_id).hasClass('searchWikidata') || $('#'+input_id).hasClass('searchVocab') || $('#'+input_id).hasClass('searchGeonamaes')) { - imported_values.each(function(){ + // b) multiple values fields + if ($('#'+formId+' [name^="'+inputId+'_"][name$="_'+subformId+'"]:not([name="'+inputId.split('_')[0]+'_'+subformId+'"])').length >0) { + var importedValues = $('#'+formId+' [name^="'+inputId.split('_')[0]+'_"][name$="_'+subformId+'"]:not([name="'+inputId.split('_')[0]+'_'+subformId+'"])'); + cloneElement.find('.label div a').remove(); + if ($('#'+inputId).hasClass('searchWikidata') || $('#'+inputId).hasClass('searchVocab') || $('#'+inputId).hasClass('searchGeonamaes')) { + importedValues.each(function(){ // imported values and URIs var value = $(this).val(); var code = value.split(",")[0]; var label = decodeURIComponent(value.split(",")[1]); - var imported_value_span = $(""+label+""); - clone_element_values.push(imported_value_span); - clone_element_values.push($(this)); + var importedValueSpan = $(""+label+""); + clonedElementValues.push(importedValueSpan); + clonedElementValues.push($(this)); $(this).remove(); }); } else { - imported_values.each(function(){ + importedValues.each(function(){ // multiple-lang literal values - clone_element_values.push($(this)); - clone_element.find('input').remove(); + clonedElementValues.push($(this)); + cloneElement.find('input').remove(); if($(this).attr('lang') != undefined) { let lang = $(this).attr('lang'); - const new_lang_item = $(''+lang+''); - clone_element.find('div').append(new_lang_item); + const newLangItem = $(''+lang+''); + cloneElement.find('div').append(newLangItem); } else { - let main_lang = $(this).val(); - clone_element.find('div a[title="text language: '+main_lang.toUpperCase()+'"]').addClass('main-lang'); + let mainLang = $(this).val(); + cloneElement.find('div a[title="text language: '+mainLang.toUpperCase()+'"]').addClass('main-lang'); } }); - clone_element.find('div a').eq(0).addClass('selected-lang'); - clone_element_values[0].show(); - console.log(clone_element_values) + cloneElement.find('div a').eq(0).addClass('selected-lang'); + clonedElementValues[0].show(); } } - // c) subrecords - if ($('[name="'+input_id+'_'+subform_id+'-subrecords"]').length>0) { + // c) subrecords fields (inner subrecords) + if ($('[name="'+inputId+'_'+subformId+'-subrecords"]').length>0) { // retrieve subrecords - var subrecords = $('[name="'+input_id+'_'+subform_id+'-subrecords"]').val().split(','); - console.log(subrecords) - var subtemplate_field_id = $(this).attr('name').replace('-subrecords', ''); - console.log($('#'+subtemplate_field_id).attr('class')) - var subrecord_cls = $('#'+subtemplate_field_id).attr('subtemplate') + var subrecords = $('[name="'+inputId+'_'+subformId+'-subrecords"]').val().split(','); + var subtemplateFieldId = $(this).attr('name').replace('-subrecords', ''); + var subrecord_cls = $('#'+subtemplateFieldId).attr('subtemplate') for (let i=0; i 0) { - var main_lang = $('#'+subrecord_label_field.attr('id').split('_')[0] + '_mainLang_' + code).val(); - console.log('#'+subrecord_label_field.attr('id').split('_')[0] + '_mainLang_' + code) - label = $('#'+subrecord_label_field.attr('id').split('_')[0]+'_'+main_lang+'_'+code).val(); - console.log('#'+subrecord_label_field.attr('id').split('_')[0]+'_'+main_lang+'_'+code) - console.log(label) + var subrecordLabelField = $('.original_subtemplate.disambiguate[class*="('+subrecordCls+')"]'); + if (subrecordLabelField.length > 0) { + var mainLang = $('#'+subrecordLabelField.attr('id').split('_')[0] + '_mainLang_' + code).val(); + label = $('#'+subrecordLabelField.attr('id').split('_')[0]+'_'+mainLang+'_'+code).val(); } } - var subrecord_value_span = $(""+label+"") - var modify_button = $('') - var delete_button = $('') - clone_element_values.push(subrecord_value_span, modify_button, delete_button); + var subrecordValueSpan = $(""+label+"") + var modifyButton = $('') + var deleteButton = $('') + clonedElementValues.push(subrecordValueSpan, modifyButton, deleteButton); } } - clone_element.find('.input_or_select').eq(0).append(clone_element_values); - subrecord_form.append(clone_element); + cloneElement.find('.input_or_select').eq(0).append(clonedElementValues); + subrecordForm.append(cloneElement); + }) + // add knowledge extractor if required + var resourceTemplate = $('[subtemplate="'+resourceClass+'"').eq(0).attr('subtemplateid'); + if (extractorsArray.includes(resourceTemplate)) { + generateExtractor(subformId,subrecordForm); + } + // save or cancel subrecord (buttons) - const subrecord_buttons = $("
"); - const save_subrecord_btn = $(""); - const cancel_subrecord_btn = $(""); + const subrecordButtons = $("
"); + const saveSubrecordButton = $(""); + const cancelSubrecordButton = $(""); - console.log(el) // SAVE SUBRECORD - save_subrecord_btn.on('click', function(e) { + saveSubrecordButton.on('click', function(e) { // generate a tag - var is_valid = check_mandatory_fields(this); - if (is_valid) { - var label_field = subrecord_form.find('.disambiguate').eq(0); - var label_main_lang = $('#'+label_field.attr('id').replace(label_field.attr('lang'), 'mainLang')).val(); - var tag_label = subrecord_form.find('.disambiguate[lang="'+label_main_lang+'"]').val() || (field_name + "-" + subform_id); + var isValid = check_mandatory_fields(this); + if (isValid) { + var labelField = subrecordForm.find('.disambiguate').eq(0); + var labelMainLang = $('#'+labelField.attr('id').replace(labelField.attr('lang'), 'mainLang')).val(); + var tagLabel = subrecordForm.find('.disambiguate[lang="'+labelMainLang+'"]').val() || (fieldName + "-" + subformId); // store all the input ids to be associated with a subrecord // append those inputs to the main record form to pass their values to the back-end application let subinputs = []; - subrecord_form.find('input:not(.btn)').each(function() { - $('#'+form_id).append($(this)); + subrecordForm.find('input:not(.btn)').each(function() { + $('#'+formId).append($(this)); $(this).hide(); if ($(this).attr('id') !== undefined) { if($(this).attr('lang')!== undefined) { @@ -2422,20 +2418,20 @@ function create_subrecord(resource_class, field_name, el, subform_id=null ) { } }; }); - el.after("
" + tag_label + ""); + el.after("
" + tagLabel + ""); // for each subtemplate field, create an hidden input value including a list of related subrecords // this is needed to streamline the creation of records (back-end application) - var subrecord_base = $("[subtemplate='"+resource_class+"']").attr('id'); // the 'id' of the 'subtemplate' field (within the main record) - var created_subrecords = $('[name="'+subrecord_base+'-subrecords"]'); - if (created_subrecords.length) { - var to_extend_value = created_subrecords.val(); - if (!created_subrecords.val().split(',').includes(subform_id)) { - created_subrecords.val(to_extend_value + "," + subform_id); + var subrecordBase = $("[subtemplate='"+resourceClass+"']").attr('id'); // the 'id' of the 'subtemplate' field (within the main record) + var createdSubrecords = $('[name="'+subrecord_base+'-subrecords"]'); + if (createdSubrecords.length) { + var toExtendValue = createdSubrecords.val(); + if (!createdSubrecords.val().split(',').includes(subformId)) { + createdSubrecords.val(toExtendValue + "," + subformId); } } else { - const new_sub = $(""); - $('#'+form_id).append(new_sub); + const newSubrecord = $(""); + $('#'+form_id).append(newSubrecord); } // hide_subform cancel_subrecord(this); @@ -2443,15 +2439,15 @@ function create_subrecord(resource_class, field_name, el, subform_id=null ) { }); // CANCEL SUBRECORD - cancel_subrecord_btn.on('click', function(e) { + cancelSubrecordButton.on('click', function(e) { // hide_subform cancel_subrecord(this); }); - subrecord_buttons.append(cancel_subrecord_btn, save_subrecord_btn); - subrecord_form.append(subrecord_buttons); - subrecord_section.append(subrecord_form); - $('.main_content').eq(0).prepend(subrecord_section); + subrecordButtons.append(cancelSubrecordButton, saveSubrecordButton); + subrecordForm.append(subrecordButtons); + subrecordSection.append(subrecordForm); + $('.main_content').eq(0).prepend(subrecordSection); } // CANCEL SUBRECORD (before adding it to #recordForm) @@ -3033,12 +3029,11 @@ function add_field(field, res_type, backend_file=null) { }; function import_subtemplate(el) { - var requested_template = el.value; var requested_name = el.options[el.selectedIndex].text; - var name_field = $(el).parent().next().find('input').eq(0); - var class_field = $(el).parent().next().next().find('input').eq(0); - var edit_field = $(el).parent().next().next().next(); + var name_field = $(el).parent().next().find('input[type="text"]').eq(0); + var class_field = $(el).parent().next().next().find('input[type="text"]').eq(0); + var edit_field = $(el).parent().next().next().next('input[type="button"]'); $(name_field).parent().show(); $(class_field).parent().show(); // make fields not modifiable unless creating a new subtemplate @@ -3124,7 +3119,7 @@ function add_disambiguate(temp_id, el) { // YASQE editor for SPARQL query patterns if (el.value == 'URI') { var field_SPARQL_constraint = $("
\ - \ + \ \ + \ + \
\ -
\ - \ +
\ + \
\
"); - $(extractor).insertAfter('.import_form'); - $('.import_form').hide(); - $('.form_row').hide(); + $(extractor).insertAfter('.import-form'); + $('#'+ul).hide(); }; -// create a form based on the selected option (API, SPARQL, static file) -function add_extractor(element) { +// create a new form based on the selected option (API, SPARQL, static file) +function addExtractor(element,extractorId) { if ($('.block_field.col-md-12').length > 0) { $('.block_field.col-md-12 section').not(":first").remove(); } - var id = extraction_number.toString(); // it will be used to create hidden inputs later - extraction_number++; - var selected = $(element).find(":selected").val(); // selected option (API, SPARQL, or static file) - console.log(selected); - $('.extractor_1').remove(); // remove previously created forms (in case the user changes the selected option) - if (selected == 'api') { - var form = "
\ - \ - \ + + var extractionNumber = extractionsObj[extractorId].length; // number of attempted extraction + var extractionId = extractorId+'-'+extractionNumber.toString(); // it will be used to create hidden inputs later + var extractionType = $(element).find(":selected").val(); // selected option (API, SPARQL, or static file) + + $('.block_field .extractor-1, .block_field hr').remove() // remove previously created forms (in case the user changes the selected option) + if (extractionType == 'api') { + var form = "
\ + \ + \
\ -
\ - \ - \ +
\ + \ +
\ + KEY\ + VALUE\ +
\ +

No parameters available: add a new one

\ +
\ + \ + \ + \ +
\ + Add new \
\ -
\ - \ - \ -
"; - } else if (selected == 'sparql') { - var form = "
\ - \ - \ +
\ + \ +
\ + KEY\ + VALUE\ +
\ +
\ + \ + \ + \ +
\ +
\ + \ + \ + \ +
\ +
\ + \ + \ + \ +
\ + Add new \ +
\ + " + /* var form = "
\ + \ + \
\ -
\ - \ - \ +
\ + \ + \ +
\ +
\ + \ + \ +
"; */ + } else if (extractionType == 'sparql') { + var form = "
\ + \ + \ +
\ +
\ + \ +
\
"; - } else if (selected == 'file' || selected == 'Select') { - var form = "
\ - \ - \ + } else if (extractionType == 'file') { + var form = "
\ + \ + \
\ -
\ - \ - \ +
\ + \ +
\
"; + } else { + var form = ""; } - var buttons = "
\ - \ - \ + + // navigation button + var buttons = "
\ + \ + \
" - // add the new form to the webpage + + // add the new form to the webpage and show YASQE editor when needed $(element).closest('.row').after(form+buttons); + if (extractionType == 'sparql' || extractionType == 'file') { + var yasqe = YASQE(document.getElementById("yasqe"), { + sparql: { + showQueryButton: false, + } + }); + //yasqe.setValue(value_to_set); + } $('.extraction_documentation').show(); $('.extraction_documentation section').hide(); - $('.extraction_documentation_'+selected).show(); + $('.extraction_documentation_'+extractionType).show(); } -function prev_extractor(to_hide, to_show, remove=false, id=null) { - $('.'+to_hide).hide(); - $('.'+to_show).show(); +// parse the extraction parameters and send requests +function nextExtractor(element, id, type) { + // retrieve extractor Id and extraction count + var splitId = id.split('-'); + var extractionCount = parseInt(splitId[2]); + var extractorId = splitId[0]+'-'+splitId[1]; + + // retrieve YASQE query (type=='file'/'sparql') + let query = ""; + var yasqeQueryRows = $('[data-id="'+id+'"]').find('.CodeMirror-code>div'); + yasqeQueryRows.each(function() { + var tokens = $(this).find('pre span span'); + tokens.each(function() { + query += $(this).hasClass('cm-ws') ? ' ' : $(this).text(); + }); + query += '\n'; + }); + + console.log(query) + + // collect all the query information and store it into an Object + const objectItem = {}; + if (type == "api") { + objectItem["type"] = "api"; + objectItem["url"] = $('#ApiUrl').val(); + objectItem["query"] = $('#ApiQuery').val().replace(/"/g, '\\"'); + objectItem["results"] = $('#ApiResults').val(); + } else if (type == "sparql") { + objectItem["type"] = "sparql"; + objectItem["url"] = $('#SparqlUrl').val(); + objectItem["query"] = query; + } else if (type == "file") { + objectItem["type"] = "file"; + objectItem["url"] = $('#FileUrl').val(); + objectItem["query"] = query; + } + + /* Object.entries(objectItem).forEach(([key, value]) => { + $('#recordForm, #modifyForm').prepend(""); + }); */ + + if (type == "api") { + // API QUERY: + // set query parameters and send the request + var jsonQuery = string_to_json(objectItem["query"]); + $.getJSON(objectItem["url"], jsonQuery, + function(data) { + // show the query results in a table + var bindings = showExtractionResult(data,type,id,objectItem); + + // store the results within the temporary Object and display the table + const jsonOutput = {'results': {'bindings': bindings}}; + objectItem["output"] = jsonOutput; + + }).error(function(jqXHR, textStatus, errorThrown) { + alert(("error: " + jqXHR.responseText)) + }) + } else if (type == "file") { + // FILE QUERY: + // modify the query to include the necessary clauses + + var bindings = callSparqlanything(objectItem["query"],id,type,objectItem["url"]); + objectItem["output"] = bindings; + } else if (type == "sparql") { + // SPARQL QUERY + // modify the query to include the necessary clauses + var bindings = callSparqlanything(objectItem["query"],id,type,objectItem["url"]) + objectItem["output"] = bindings; + } + + // add the extraction information, including the results, to the Extractions Object + var newExtractionObj = {} + newExtractionObj[extractionCount] = objectItem; + extractionsObj[extractorId][extractionCount-1] = newExtractionObj; +} + +// go back to the previous Extraction page to modify query parameters / hide the Extraction form +function prevExtractor(toHide, toShow, remove=false, id=null) { + $('.'+toHide).hide(); + $('.'+toShow).show(); if (remove) { - const button = $('.import_form').eq(0); - if (id && $('#query_result_' + id).length>0) { - button.find(".imported_graphs").prepend($("

  • ")); - var results = JSON.parse($('#query_result_' + id).val()).results.bindings; - for (let idx = 0; idx < results.length; idx++) { - for (const key in results[idx]) { - console.log(results[idx][key]); - - if (results[idx][key].type === "literal" && !results[idx][key].value.startsWith("https://") && !results[idx][key].value.startsWith("http://")) { - var label = results[idx][key].value; - } else if (results[idx][key].type === "uri" || results[idx][key].value.startsWith("https://") || results[idx][key].value.startsWith("http://")) { - var uri = results[idx][key].value; + + // find the Extractions List and access the results dict inside the Extractions Object + const extractionListId = id.split('-').slice(0, 2).join('-'); + const extractionNumber = parseInt(id.split('-')[2]); + if ('output' in extractionsObj[extractionListId][extractionNumber-1][extractionNumber]) { + var results = extractionsObj[extractionListId][extractionNumber-1][extractionNumber].output.results.bindings; + + // if results exist, create a new list item to collect each retrieved URI,label pair in the form of a tag (containing an hidden input) + if (results.length>0) { + $('#imported-graphs-'+extractionListId).prepend($("

  • ")); + + for (let idx = 0; idx < results.length; idx++) { + for (const key in results[idx]) { + console.log(results[idx][key]); + + if (results[idx][key].type === "literal" && !results[idx][key].value.startsWith("https://") && !results[idx][key].value.startsWith("http://")) { + var label = results[idx][key].value; + } else if (results[idx][key].type === "uri" || results[idx][key].value.startsWith("https://") || results[idx][key].value.startsWith("http://")) { + var uri = results[idx][key].value; + } } + $('#imported-graphs-'+extractionListId).find("#graph-" + id).append("" + label + ""); } - button.find("#graph-" + id).append("" + label + ""); } } - $('.block_field.col-md-12').replaceWith(button); - button.show(); - $('.homeheading').eq(0).attr('class', 'homeheading col-md-8 col-lg-8 col-sm-8'); - $('.homeheading.col-md-4.col-sm-4.col-lg-4').show(); + + // hide the Extraction documentation and the Extraction form, then show the list of Extractions $('.extraction_documentation').hide(); + $('#imported-graphs-'+extractionListId).parent().next('.block_field').hide(); + $('#imported-graphs-'+extractionListId).show(); } } @@ -3701,7 +3874,126 @@ function delete_extractor(id) { $('#graph-'+id).remove(); } -function extractor_pagination(results) { +function string_to_json(input_string) { + const rows = input_string.split('\n'); + const json_output = {}; + + for (const row of rows) { + const [key, val] = row.split(','); + const k = key.trim(); + const v = val.trim(); + json_output[k] = v; + } + + return json_output +} + +function showExtractionResult(jsonData,type,id,objectItem=null) { + console.log(jsonData) + // base module + let bindings = []; + const resultSection = $("
    '); + + // store the results as a JSON object following the SPARQL response structure + if (type==='api') { + resultTable.append("LABELURI"); + + // set the results paths + var jsonResults = string_to_json(objectItem["results"]); + var mainPath = jsonResults.array.split("."); + let resultsArray = jsonData; + mainPath.forEach(key => { + resultsArray = resultsArray[key]; + }); + + resultsArray.forEach(function(res) { + // extract a label for each term + let labelPath = jsonResults.label.split("."); + let label = res; + labelPath.forEach(key => { + label = label[key]; + }); + // extract the URI value for each term + let uriPath = jsonResults.uri.split("."); + let uri = res; + uriPath.forEach(key => { + uri = uri[key]; + }); + + // create a new table row, append it to the table, and store each term information + var resultTableRow = $('' + label + '' + uri + ''); + resultTable.append(resultTableRow); + bindings.push({"uri": {'value':uri, 'type':'uri'}, 'label': {'value':label, 'type':'literal'}}); + }); + } else if (type==='sparql' || type==='file') { + + var labels = jsonData.head.vars + var tr = $(''); + for (var i = 0; i < labels.length; i++) { + var th = $('' + labels[i] + ''); + tr.append(th); + } + resultTable.append(tr); + + bindings = jsonData.results.bindings + for (let idx=0; idx'); + for (let i=0; i"+result[label].value+""; + } else { + var item = result[label].value; + } + var td = $('' + item + '') + resultTableRow.append(td); + } + resultTable.append(resultTableRow) + } + } + resultSection.append(resultTable); + + // manage navigation buttons and results pagination + var buttonList = "
    \ + \ + \ +
    "; + $('.extractor-1').hide(); + $('.block_field').append(resultSection); + $('.block_field').append(buttonList); + if (bindings.length > 25) {extractorPagination(bindings)}; + + return bindings +} + +// call back-end API to perform SPARQL.Anything queries +function callSparqlanything(q, id, type, endpoint) { + // modify the query to make it ready for SPARQL.Anything + var encoded; + if (type === 'file') { + encoded = encodeURIComponent(q.includes("") ? q : q.replace("{", "{ SERVICE {").replace("}", "}}")); + } else if (type === 'sparql') { + encoded = q.includes("SERVICE") ? encodeURIComponent(q) : encodeURIComponent(q.replace("{", "{ SERVICE <" + endpoint + "> {").replace("}", "}}")); + }; + + // send the query to the back-end API and parse the results + $.ajax({ + type: 'GET', + url: '/sparqlanything?q=' + encoded, + success: function(resultsJsonObject) { + // show results inside a table + var bindings = showExtractionResult(resultsJsonObject,type,id); + return bindings; + }, + error: function() { + alert(("error: check your parameters")) + } + }); +} + +function extractorPagination(results) { var length = results.length; var remainder = length%25; if (remainder > 0) { @@ -3710,193 +4002,33 @@ function extractor_pagination(results) { var total = Math.floor(length/25); } if (length > 25) { - var hide_results = $('.extractor_2').find('tr').slice(25, length); + var hide_results = $('.extractor-2').find('tr').slice(25, length); hide_results.addClass('hidden-result'); } - var page_section = $('
    ') + var page_section = $('
    ') for (let n=0; n'); + var button=$(''); page_section.append(button) } $('.block_field').append(page_section); } -function change_results_page(page_n, length) { +function changeResultsPage(page_n, length) { var starting_result = 25 * (parseInt(page_n)-1); console.log(page_n, starting_result) - $('.extractor_2').find('tr').addClass('hidden-result'); + $('.extractor-2').find('tr').addClass('hidden-result'); if (length >= starting_result+25) { - var show_results = $('.extractor_2').find('tr').slice(starting_result, starting_result+25); + var show_results = $('.extractor-2').find('tr').slice(starting_result, starting_result+25); } else { - var show_results = $('.extractor_2').find('tr').slice(starting_result, length); + var show_results = $('.extractor-2').find('tr').slice(starting_result, length); } show_results.removeClass('hidden-result'); - $('.extractor_2').find('th').parent().removeClass('hidden-result'); + $('.extractor-2').find('th').parent().removeClass('hidden-result'); window.scrollTo(0, 0); } -function call_sparqlanything(encoded, id, element_id, type) { - console.log(encoded) - $.ajax({ - type: 'GET', - url: '/sparqlanything?q=' + encoded, - success: function(result_json) { - console.log(result_json); - $(element_id).prepend(""); - var labels = result_json.head.vars; - var result_sec = $("
    '); - - var tr = $(''); - for (var i = 0; i < labels.length; i++) { - var th = $('' + labels[i] + ''); - tr.append(th); - } - result_table.append(tr); - - for (let res_idx=0; res_idx'); - for (let i=0; i"+result[label].value+""; - } else { - var item = result[label].value; - } - var td = $('' + item + '') - result_tr.append(td); - } - result_table.append(result_tr) - } - result_sec.append(result_table); - $('.extractor_1').hide(); - $('.block_field').append(result_sec); - if (result_json.results.bindings.length > 25) {extractor_pagination(result_json.results.bindings)}; - var buttons = "
    \ - \ - \ -
    "; - $('.block_field').append(buttons); - - }, - error: function() { - alert(("error: check your parameters")) - } - }); -} - -function string_to_json(input_string) { - const rows = input_string.split('\n'); - const json_output = {}; - - for (const row of rows) { - const [key, val] = row.split(','); - const k = key.trim(); - const v = val.trim(); - json_output[k] = v; - } - - return json_output -} - -function next_extractor(element, id, type) { - if ($('#recordForm').length >0) { - var element_id = '#recordForm'; - } else { - var element_id = '#modifyForm'; - } - - const object_item = {}; - if (type == "api") { - object_item["-TYPE"] = "api"; - object_item["-URL"] = $('#ApiUrl').val(); - object_item["-QUERY"] = $('#ApiQuery').val().replace(/"/g, '\\"'); - object_item["-RESULTS"] = $('#ApiResults').val(); - } else if (type == "sparql") { - object_item["-TYPE"] = "sparql"; - object_item["-URL"] = $('#SparqlUrl').val(); - object_item["-QUERY"] = $('#SparqlQuery').val(); - } else if (type == "file") { - object_item["-TYPE"] = "file"; - object_item["-URL"] = $('#FileUrl').val(); - object_item["-QUERY"] = $('#FileQuery').val(); - } - console.log(object_item, type) - Object.entries(object_item).forEach(([key, value]) => { - $(element_id).prepend(""); - }); - - if (type == "api") { - var json_query = string_to_json(object_item["-QUERY"]); - $.getJSON(object_item["-URL"], json_query, - function(data) { - - var json_results = string_to_json(object_item["-RESULTS"]) - var main_path = json_results.array.split("."); - let results_array = data; - main_path.forEach(key => { - results_array = results_array[key]; - }); - - var result_sec = $("
    LABELURI'); - const bindings = []; - results_array.forEach(function(res) { - // extract a label for each term - let label_path = json_results.label.split("."); - let label = res; - label_path.forEach(key => { - label = label[key]; - }); - // extract the URI value for each term - let uri_path = json_results.uri.split("."); - let uri = res; - uri_path.forEach(key => { - uri = uri[key]; - }); - - // create a variable to store all the relevant information about each term - var result_tr = $('' + label + '' + uri + ''); - result_table.append(result_tr) - - bindings.push({"uri": {'value':uri, 'type':'uri'}, 'label': {'value':label, 'type':'literal'}}) - }); - const json_output = {'results': {'bindings': bindings}}; - result_sec.append(result_table); - - - $('.extractor_1').hide(); - $('.block_field').append(result_sec); - var handling_list = "
    \ - \ - \ -
    "; - $('.block_field').append(handling_list); - }).error(function(jqXHR, textStatus, errorThrown) { - alert(("error: " + jqXHR.responseText)) - }) - - } else if (type == "file") { - - if (object_item["-QUERY"].includes("") && object_item["-QUERY"].includes("SERVICE")) { - call_sparqlanything(encodeURIComponent(object_item["-QUERY"]), id, element_id, type); - } else { - call_sparqlanything(encodeURIComponent(object_item["-QUERY"].replace("{", "{ SERVICE {").replace("}", "}}")), id, element_id, type); - } - } else if (type == "sparql") { - if (object_item["-QUERY"].includes("SERVICE")) { - call_sparqlanything(encodeURIComponent(object_item["-QUERY"]), id, element_id, type); - } else { - call_sparqlanything(encodeURIComponent(object_item["-QUERY"].replace("{", "{ SERVICE <"+object_item["-URL"]+"> {").replace("}", "}}")), id, element_id, type); - } - } -} - - // TODO: bring it to the right position within this file function check_mandatory_fields(subrecord_btn=false){ var is_valid = true; diff --git a/templates/record.html b/templates/record.html index e6f88cc..424b47d 100644 --- a/templates/record.html +++ b/templates/record.html @@ -1,4 +1,4 @@ -$def with(record_form, pageID, user, alert, limit, is_git_auth,invalid,project,template,query_templates,knowledge_extractor) +$def with(record_form,pageID,user,alert,limit,is_git_auth,invalid,project,template,query_templates,knowledge_extractor) $var user = user $var is_git_auth = is_git_auth $var project = project @@ -53,18 +53,6 @@

    Thanks for helping $project to grow!

    $$('#$id').prepend($$(''));
    - - $if knowledge_extractor: - -
    -
    ENTITIES
    -
      -
    • -
    -
    -

    What did you find?

    @@ -142,6 +130,10 @@

    What did you find?

    + + + + $if field['value'] == 'URI':
    - +
    -
    @@ -351,4 +350,3 @@
    Knowledge Extraction
    - diff --git a/utils.py b/utils.py index e81cb28..cde833b 100644 --- a/utils.py +++ b/utils.py @@ -310,7 +310,7 @@ def updateTemplateList(res_name=None,res_type=None,remove=False): def get_template_from_class(res_type): print("###res_type",res_type) - """ Return the tempalte file path given the URI of the OWL class + """ Return the template file path given the URI of the OWL class Parameters ---------- @@ -324,6 +324,22 @@ def get_template_from_class(res_type): res_template = [t["template"] for t in data if t["type"] == res_type][0] return res_template +def get_class_from_template(res_tpl): + print("###res_template",res_tpl) + """ Return the URI of the OWL class given the template path + + Parameters + ---------- + res_tpl: str + Path associated to the template. Becomes dictionary value + """ + + with open(TEMPLATE_LIST,'r') as tpl_file: + data = json.load(tpl_file) + + res_type = [t["type"] for t in data if t["template"] == res_tpl][0] + return res_type + def update_ask_class(template_path,res_name,remove=False): """ Update the list of existing templates in ask_class.json. The form is shown when creating a new record and let the user @@ -456,25 +472,28 @@ def update_skos_vocabs(d, skos): # KNOWLEDGE EXTRACTION -def has_extractor(id, modify=False): +def has_extractor(res_id, modify=False): # checks whether a template allows some knowledge extraction if modify: with open(conf.knowledge_extraction,'r') as ke_file: data = json.load(ke_file) - if id in data: + if res_id in data: return True else: return False else: - with open(id,'r') as tpl_file: + result = set() + with open(res_id,'r') as tpl_file: data = json.load(tpl_file) - print(data) if data: for field in data: if 'knowledgeExtractor' in field and field['knowledgeExtractor'] == 'True': - return True - return False + result.add(res_id) + elif 'import_subtemplate' in field and field['import_subtemplate'] != '': + # iterate over sub-templates + result.update(has_extractor(field['import_subtemplate'], modify=False)) + return result def update_knowledge_extraction(data, KE_file): # stores the knowledge extractions set by the user