Skip to content

Commit

Permalink
save hidden triples #11; modify/remove i. t. #10
Browse files Browse the repository at this point in the history
#11 : introduced a mechanism to retrieve and save previously added hidden triples while updating a named graph;
#10 : introduced the possibility to integrate advanced field types (e.g. Textbox > entity; SKOS vocabularies; etc.) within subrecord forms. Automatic suggestions' visualisation should be improved (i.e., needs to be properly placed within the corresponding section). Moreover, two novel functions have been introduced to either remove entire subrecords or modify them (the latter function is not over yet: advanced fields require further attention)
  • Loading branch information
Sebastiano-G committed Feb 14, 2024
1 parent ff320cf commit bfb78a6
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 66 deletions.
41 changes: 30 additions & 11 deletions mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,20 @@ def inputToRDF(recordData, userID, stage, knowledge_extraction, graphToClear=Non
if creatorIRI is not None and creatorLabel is not None:
wd.add(( URIRef(base+graph_name+'/'), PROV.wasAttributedTo, URIRef(creatorIRI) ))
wd.add(( URIRef(creatorIRI), RDFS.label , Literal(creatorLabel ) ))

# retrieve hidden triples (to be saved) and re-introduce them in the named graph
to_be_saved = queries.saveHiddenTriples(graphToClear, tpl_form)
if to_be_saved:
for binding in to_be_saved['results']['bindings']:
subject = URIRef(binding['subject']['value'])
for predicate, obj in binding.items():
if predicate != 'subject':
if obj['type'] == 'uri':
object_ = URIRef(obj['value'])
else:
object_ = Literal(obj['value'])
wd.add((subject, URIRef(predicate), object_))

queries.clearGraph(graphToClear)
wd.add(( URIRef(base+graph_name+'/'), PROV.generatedAtTime, Literal(datetime.datetime.now(),datatype=XSD.dateTime) ))
wd.add(( URIRef(base+graph_name+'/'), URIRef('http://dbpedia.org/ontology/currentStatus'), Literal(stage, datatype="http://www.w3.org/2001/XMLSchema#string") ))
Expand All @@ -110,6 +124,7 @@ def inputToRDF(recordData, userID, stage, knowledge_extraction, graphToClear=Non
if len(is_any_disambiguate) == 0:
wd.add(( URIRef(base+graph_name+'/'), RDFS.label, Literal("no title") ))

fields = [input_field for input_field in fields if input_field['hidden'] == 'False']
for field in fields:
if field['type'] not in ['KnowledgeExtractor', 'Subtemplate']:
# URI, Textarea (only text at this stage), Literals
Expand Down Expand Up @@ -212,31 +227,36 @@ def inputToRDF(recordData, userID, stage, knowledge_extraction, graphToClear=Non
# convert the dict of inputs into a series of nested dictionaries to be parsed as single records
def process_subrecords(data, id):
results = {}
created_subrecords = [key for key in data if key.startswith(id+"-")]
created_subrecords = [key for key in data if key.startswith(id+"__")]
if created_subrecords != []:
for subrecord in created_subrecords:
add_results = {}
subrecord_split = subrecord.split('-')
subrecord_split = subrecord.split('__')
prefix, num = subrecord_split[0], subrecord_split[-1]
subrecord_fields = data[subrecord].split(',')
inner_subrecords = [key for item in subrecord_fields for key in data.keys() if key.startswith(item + "-")]
inner_subrecords = [key for item in subrecord_fields for key in data.keys() if key.startswith(item + "__")]
for key in subrecord_fields:
if data[key] != "":
add_results[key.split('-')[0]] = data[key]
add_results[key.split('__')[0]] = data[key]
else:
inner_subrecords = [inner_subrecord for inner_subrecord in data.keys() if inner_subrecord.startswith(key + "-")]
for inner_subrecord in inner_subrecords:
if inner_subrecord.startswith(key + '-'):
inner_subrecord_split = inner_subrecord.split('-')
inner_subrecords = [inner_subrecord for inner_subrecord in data.keys() if inner_subrecord.startswith(key + "__")]
if inner_subrecords != []:
for inner_subrecord in inner_subrecords:
inner_subrecord_split = inner_subrecord.split('__')
inner_prefix, inner_num = inner_subrecord_split[0], inner_subrecord_split[-1]
add_results[inner_prefix] = {
inner_num: process_subrecords(data, inner_subrecord)
}
else:
imported_values = [import_key for import_key in data.keys() if import_key.startswith(key + "-")]
for imported_value in imported_values:
new_key = imported_value.split('__')[0] + "-" + imported_value.split('-')[-1]
add_results[new_key] = data[imported_value]
if prefix in results:
results[prefix][num] = add_results
else:
results[prefix] = { num: add_results }
else:
elif data[id] != "":
for el in data[id].split(','):
results[el.split('-')[0]] = data[el]
return results
Expand All @@ -250,5 +270,4 @@ def find_label(tpl, subrecord, alternative_label):

# Add a mechanism to handle potential Templates without a Primary Key (e.g. the primary key has been set to "hidden")
label = subrecord[label_field_id] if label_field_id in subrecord else alternative_label+"-"+subrecord['recordID']
return label

return label
28 changes: 28 additions & 0 deletions queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,31 @@ def retrieve_extractions(res_uri):
next_id = max(ke_dict[res_uri.split("/")[-1]], key=lambda x: int(x["internalID"]))
res_dict['next_id'] = int(next_id['internalID']) + 1
return res_dict

def saveHiddenTriples(graph, tpl):
with open(tpl) as template:
fields = json.load(template)

results = []
hidden_fields = [field for field in fields if field['hidden'] == 'True']
patterns = [ 'OPTIONAL {?subject <'+hidden_field['property']+'> ?'+hidden_field['id']+'.}. ' if hidden_field['value'] in ['Literal','Date','gYearMonth','gYear','URL'] else 'OPTIONAL {?subject <'+hidden_field['property']+'> ?'+hidden_field['id']+'. ?'+hidden_field['id']+' rdfs:label ?'+hidden_field['id']+'_label .} .' for hidden_field in hidden_fields if 'value' in hidden_field and hidden_field['hidden'] == 'True']
if patterns != []:
patterns_string = ''.join(patterns)
queryNGraph = '''
PREFIX base: <'''+conf.base+'''>
PREFIX schema: <https://schema.org/>
SELECT DISTINCT *
WHERE {
GRAPH <'''+graph+'''>
{
'''+patterns_string+'''
}
}
'''
print(queryNGraph)
sparql = SPARQLWrapper(conf.myEndpoint)
sparql.setQuery(queryNGraph)
sparql.setReturnFormat(JSON)
results = sparql.query().convert()
print(results)
return results
173 changes: 118 additions & 55 deletions static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,17 @@ $(document).ready(function() {
});

// search WD, VIAF, my data, vocabs, years + add URLs
$("input[type='text']").click(function () {
$(".main_content").on("click", "input[type='text']", function () { // make the onclick function valid for later generated inputs
searchID = $(this).attr('id');

const searchresult = $('#searchresult').detach();
if ($(this).closest('.subform_section').length) {
$(this).closest('.subform_section').prepend(searchresult);
} else if ($(this).closest('form').length) {
$(this).closest('form').parent().after(searchresult);
}


if ( $(this).hasClass('searchWikidata') ) {
searchWD(searchID);
};
Expand Down Expand Up @@ -447,14 +455,14 @@ function searchGeonames(searchterm) {
format: "json",
},
function(data) {
// autocomplete positioning
// autocomplete positioning;
var position = $('#'+searchterm).position();
var leftpos = position.left+15;
var leftpos = $('.subform_section').length !== 0 ? position.left-35 : position.left+15;
var offset = $('#'+searchterm).offset();
var height = $('#'+searchterm).height();
var width = $('#'+searchterm).width();
var top = offset.top + height + "px";
var right = offset.left + width + "px";
var top = $('.subform_section').length !== 0 ? offset.top - $('.subform_section').offset().top + height + "px" : offset.top + height + "px";
var max_width = $('.subform_section').length !== 0 ? '90%' : '600px';
console.log(max_width);

$('#searchresult').css( {
'position': 'absolute',
Expand All @@ -463,7 +471,7 @@ function searchGeonames(searchterm) {
'z-index':1000,
'background-color': 'white',
'border':'solid 1px grey',
'max-width':'600px',
'max-width':max_width,
'border-radius': '4px'
});
$("#searchresult").empty();
Expand Down Expand Up @@ -605,14 +613,14 @@ function searchWD(searchterm) {
limit: 5,
},
function(data) {
// autocomplete positioning
// autocomplete positioning;
var position = $('#'+searchterm).position();
var leftpos = position.left+15;
var leftpos = $('.subform_section').length !== 0 ? position.left-35 : position.left+15;
var offset = $('#'+searchterm).offset();
var height = $('#'+searchterm).height();
var width = $('#'+searchterm).width();
var top = offset.top + height + "px";
var right = offset.left + width + "px";
var top = $('.subform_section').length !== 0 ? offset.top - $('.subform_section').offset().top + height + "px" : offset.top + height + "px";
var max_width = $('.subform_section').length !== 0 ? '90%' : '600px';
console.log(max_width);

$('#searchresult').css( {
'position': 'absolute',
Expand All @@ -621,7 +629,7 @@ function searchWD(searchterm) {
'z-index':1000,
'background-color': 'white',
'border':'solid 1px grey',
'max-width':'600px',
'max-width':max_width,
'border-radius': '4px'
});
$("#searchresult").empty();
Expand Down Expand Up @@ -1046,26 +1054,25 @@ function searchVocab(searchterm) {

$("#searchresult").show();

var position = $('#'+searchterm).position();
var leftpos = position.left+80;
var offset = $('#'+searchterm).offset();
var height = $('#'+searchterm).height();
var width = $('#'+searchterm).width();
var top = offset.top + height + "px";
var right = offset.left + width + "px";

$('#searchresult').css( {
'position': 'absolute',
'margin-left': leftpos+'px',
'top': top,
'z-index':1000,
'background-color': 'white',
'border':'solid 1px grey',
'max-width':'600px',
'border-radius': '4px',
'max-height': '300px',
'overflow-y': 'auto'
});
// autocomplete positioning;
var position = $('#'+searchterm).position();
var leftpos = $('.subform_section').length !== 0 ? position.left-25 : position.left+80;
var offset = $('#'+searchterm).offset();
var height = $('#'+searchterm).height();
var top = $('.subform_section').length !== 0 ? offset.top - $('.subform_section').offset().top + height + "px" : offset.top + height + "px";
var max_width = $('.subform_section').length !== 0 ? '90%' : '600px';
console.log(max_width);

$('#searchresult').css( {
'position': 'absolute',
'margin-left': leftpos+'px',
'top': top,
'z-index':1000,
'background-color': 'white',
'border':'solid 1px grey',
'max-width':max_width,
'border-radius': '4px'
});
$("#searchresult").empty();
options.forEach(function(option) {
// each option (i.e., retrieved term) has this structure: URI,LABEL,VOCABULARY
Expand Down Expand Up @@ -1249,10 +1256,8 @@ function checkPriorRecords(elem) {
});
};

// create subrecords
function create_subrecord(resource_class, field_name, el) {
// handle multiple subform
//var subform_sections = check_subform_sections();
// set the webpage to display a new subform
function replace_existing_subforms() {
if ($('.subform_section').length) {
$('.subform_section').each(function () {
var right_css = parseInt($(this).css('right'));
Expand All @@ -1261,7 +1266,13 @@ function create_subrecord(resource_class, field_name, el) {
} else {
$('body').after("<div class='modal-previewMM'></div>");
}
}

// create subrecords
function create_subrecord(resource_class, field_name, el) {
// handle multiple subform
//var subform_sections = check_subform_sections();
replace_existing_subforms();

const subrecord_section = $("<section class='subform_section col-md-12 col-sm-4'></section>");
const subform_id = Date.now().toString();
Expand All @@ -1274,54 +1285,52 @@ function create_subrecord(resource_class, field_name, el) {
const clone_element = $(this).parent().parent().clone();
clone_element.attr("style", "display: block");
clone_element.find('input').removeClass('original_subtemplate');
console.log(clone_element.html())

// associate proper input_ids to input fields belonging to the subrecord form
var input_id = clone_element.find('input').attr('id');
var class_occurences = $("input[id*='"+input_id+"']").length;
clone_element.find('input').attr('id', input_id+"-"+class_occurences.toString())
clone_element.find('input').attr('name', input_id+"-"+class_occurences.toString())
clone_element.find('input').attr('id', input_id+"__"+class_occurences.toString())
clone_element.find('input').attr('name', input_id+"__"+class_occurences.toString())
subrecord_form.append(clone_element);
})

// save or cancel subrecord
const subrecord_buttons = $("<section class='row subform_buttons buttonsSection'></section>");
const save_subrecord_btn = $("<input id='subrecord_save' class='btn btn-dark' style='margin-left:20px' value='Add''>");
const cancel_subrecord_btn = $("<input id='subrecord_cancel' class='btn btn-dark' style='margin-left:20px' value='Cancel' onclick='cancel_subrecord(this)'>");
const cancel_subrecord_btn = $("<input id='subrecord_cancel' class='btn btn-dark' style='margin-left:20px' value='Cancel'>");

// SAVE
save_subrecord_btn.bind('click', function(e) {
save_subrecord_btn.on('click', function(e) {
// generate a tag
if (subrecord_form.find('.disambiguate').length) {
var tag_label = subrecord_form.find('.disambiguate').val();
} else {
var tag_label = field_name + "-" + ($('.tag-subrecord.'+resource_class).length + 1).toString();
};
var tag_label = subrecord_form.find('.disambiguate').val() || (field_name + "-" + $(".tag-subrecord[class~='"+resource_class+"']").length + 1);
var subinputs = [];
subrecord_form.find('input:not(.btn)').each(function() {
$("#recordForm").append($(this));
$(this).hide();
subinputs.push($(this).attr('id'));
if ($(this).attr('id') !== undefined) {subinputs.push($(this).attr('id'))};
});
var subrecord_index = $("[subtemplate='"+resource_class+"']").parent().parent().find('.tag-subrecord').length + 1;
var subrecord_id = $("[subtemplate='"+resource_class+"']").attr('id') + "-" + subrecord_index;
$(el).after("<br/><span class='tag-subrecord "+resource_class+"'>" + tag_label + "</span><i class='far fa-edit'></i><i class='far fa-trash-alt'></i>");
var subrecord_id = $("[subtemplate='"+resource_class+"']").attr('id') + "__" + subrecord_index;
$(el).after("<br/><span id='"+subrecord_id+"-tag' class='tag-subrecord "+resource_class+"'>" + tag_label + "</span><i class='far fa-edit' onclick='modify_subrecord(\""+subrecord_id+"\", keep=true)'></i><i class='far fa-trash-alt' onclick='modify_subrecord(\""+subrecord_id+"\", keep=false)'></i>");
$('#recordForm').append("<input type='hidden' name='"+subrecord_id+"' id='"+subrecord_id+"' value='"+subinputs.toString()+"'></input>");

// hide_subform
cancel_subrecord(this);
});
// CANCEL
cancel_subrecord_btn.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);

$('.main_content').eq(0).prepend(subrecord_section);
}

// CANCEL SUBRECORD
// CANCEL SUBRECORD (before adding it to #recordForm)
function cancel_subrecord(subrecord_section) {
console.log(subrecord_section)
if ($('.subform_section').length > 1) {
$('.subform_section').each(function () {
var right_css = parseInt($(this).css('right'));
Expand All @@ -1330,9 +1339,63 @@ function cancel_subrecord(subrecord_section) {
} else {
$('.modal-previewMM').remove();
}
$('main form').append($('#searchresult'));
$(subrecord_section).closest('.subform_section').remove();
};

// DELETE or MODIFY SUBRECORD (after it has been added to #recordForm)
function modify_subrecord(sub_id, keep) {
var original_subtemplate_id = sub_id.split("__")[0];
var original_subtemplate_class = $('#'+original_subtemplate_id).attr('subtemplate');
console.log(original_subtemplate_class, sub_id)

if (!keep) {
// remove all inputs
var inner_inputs = $('#'+sub_id).val().split(",");
delete_inner_subrecord(inner_inputs); // collect nested inputs and remove them
$('#'+sub_id+'-tag').next('i').remove();
$('#'+sub_id+'-tag').next('i').remove();
$('#'+sub_id+'-tag').remove();
$('#'+sub_id).remove();
}
else {
// recollect the first level nested inputs to be displayed
var inner_inputs = $('#'+sub_id).val().split(",");

// recreate subrecord_section
var field_name = $('#'+sub_id+'-tag').parent().prev().text();
var el = $('#'+sub_id+'-tag').prev('.fa-plus-circle');
create_subrecord(original_subtemplate_class, field_name, el);

for (let i=0; i<inner_inputs.length; i++) {
var input = $('#'+inner_inputs[i]);
var shortened_id = inner_inputs[i].split("__").slice(0, -1).join("__");
var new_input = $('.subform_section [id*="'+shortened_id+'__"]');
if (input.val() !== "") {
new_input.replaceWith(input.show());
// FINISH HERE:
/* still need to add a system to recreate inner-subrecords and all those fields associated with a tag (e.g. Entity) */
}
}
}
}

function delete_inner_subrecord(inner_inputs) {
for (let i = 0; i < inner_inputs.length; i++) {
if ($("#"+inner_inputs[i]).attr('subtemplate')) {
console.log(inner_inputs[i])
var recursion_inputs = $("[id*="+inner_inputs[i]+"__]");
console.log(recursion_inputs)
if (recursion_inputs.length) {
for (let y = 0; y < recursion_inputs.length; y++) {
delete_inner_subrecord($(recursion_inputs[y]).val().split(","));
}
}
}
$("[id*="+inner_inputs[i]+"]").remove();
}
}

////////////////////
// PUBLISH RECORD //
///////////////////
Expand Down

0 comments on commit bfb78a6

Please sign in to comment.