Commit 23aaf13e authored by Romain Loth's avatar Romain Loth

Documents view: add 'trashAll' checkbox and smarter duplicates presentation

parent 3924b0fd
...@@ -188,11 +188,12 @@ function toggleFavstatus (rec_id) { ...@@ -188,11 +188,12 @@ function toggleFavstatus (rec_id) {
}); });
} }
function transformContent2(rec_id) { function transformContent2(rec_id, trClass) {
// pr("\t\ttransformContent2: "+rec_id) // pr("\t\ttransformContent2: "+rec_id)
var elem = AjaxRecords[rec_id]; var elem = AjaxRecords[rec_id];
// pr("\t"+elem.rawtitle) // pr("\t"+elem.rawtitle)
var result = {} var result = {}
if (elem["del"]) { if (elem["del"]) {
result["id"] = elem["id"] result["id"] = elem["id"]
result["short_date"] = '<strike>'+elem["short_date"]+'</strike>' result["short_date"] = '<strike>'+elem["short_date"]+'</strike>'
...@@ -200,7 +201,13 @@ function transformContent2(rec_id) { ...@@ -200,7 +201,13 @@ function transformContent2(rec_id) {
result["docurl"] = '<strike>'+elem["docurl"]+'</strike>' result["docurl"] = '<strike>'+elem["docurl"]+'</strike>'
result["isFavorite"] = favstatusToStar(rec_id, elem["isFavorite"], boolStrike=true) result["isFavorite"] = favstatusToStar(rec_id, elem["isFavorite"], boolStrike=true)
result["rawtitle"] = elem["rawtitle"] result["rawtitle"] = elem["rawtitle"]
result["del"] = '<input id='+rec_id+' onclick="overRide(this)" type="checkbox" checked/>' if (trClass == "normalrow" || trClass == "duplrowdel") {
result["del"] = '<input id='+rec_id+' class="trash1" onclick="toggleTrashIt(this)" type="checkbox" checked/>'
}
else if (trClass=="duplrowkeep") {
// forbid deletion for one of the duplicates
result["del"] = ''
}
} else { } else {
result["id"] = elem["id"] result["id"] = elem["id"]
result["short_date"] = elem["short_date"] result["short_date"] = elem["short_date"]
...@@ -208,16 +215,22 @@ function transformContent2(rec_id) { ...@@ -208,16 +215,22 @@ function transformContent2(rec_id) {
result["docurl"] = elem["docurl"] result["docurl"] = elem["docurl"]
result["isFavorite"] = favstatusToStar(rec_id, elem["isFavorite"]) result["isFavorite"] = favstatusToStar(rec_id, elem["isFavorite"])
result["rawtitle"] = elem["rawtitle"] result["rawtitle"] = elem["rawtitle"]
result["del"] = '<input id='+rec_id+' onclick="overRide(this)" type="checkbox"/>' if (trClass == "normalrow" || trClass == "duplrowdel") {
result["del"] = '<input id='+rec_id+' class="trash1" onclick="toggleTrashIt(this)" type="checkbox"/>'
}
else if (trClass=="duplrowkeep") {
result["del"] = ''
}
} }
return result; return result;
} }
function overRide(elem) { function toggleTrashIt(boxElem) {
var id = elem.id var id = boxElem.id // row_id in the table (not ngram_id)
var val = elem.checked var val = boxElem.checked
console.log("striking: ") console.log("striking =>", val)
console.log(AjaxRecords[id]) console.log("record", AjaxRecords[id])
// MyTable.data('dynatable').settings.dataset.originalRecords[id]["del"] = val; // MyTable.data('dynatable').settings.dataset.originalRecords[id]["del"] = val;
AjaxRecords[id]["del"] = val; AjaxRecords[id]["del"] = val;
...@@ -229,13 +242,15 @@ function overRide(elem) { ...@@ -229,13 +242,15 @@ function overRide(elem) {
MyTable.data('dynatable').dom.update(); MyTable.data('dynatable').dom.update();
} }
function transformContent(rec_id , header , content) { // function transformContent(rec_id , header , content) {
if(header=="del") { // console.warn("hello transformContent1")
// pr("\t\ttransformContent1: "+rec_id) // if(header=="del") {
if(content==true) return '<input id='+rec_id+' onclick="overRide(this)" type="checkbox" checked/>' // // pr("\t\ttransformContent1: "+rec_id)
if(content==false) return '<input id='+rec_id+' onclick="overRide(this)" type="checkbox"/>' // if(content==true) return '<input id='+rec_id+' onclick="toggleTrashIt(this)" type="checkbox" checked/>'
} else return content; // if(content==false) return '<input id='+rec_id+' onclick="toggleTrashIt(this)" type="checkbox"/>'
} // }
// else return content;
// }
$("#move2trash") $("#move2trash")
...@@ -271,22 +286,43 @@ $("#move2trash") ...@@ -271,22 +286,43 @@ $("#move2trash")
//generic enough //generic enough
function ulWriter(rowIndex, record, columns, cellWriter) { function ulWriter(rowIndex, record, columns, cellWriter) {
var trClass = 'normalrow'
// special case ------------------------------------------------- 8< -------
// set the tr class to show duplicates in another light
// normalrow|duplrowdel|duplrowkeep (the last 2 for duplicate case)
if (dupFlag) {
// console.log("dupFlag in ulWriter")
recId = RecDict[record.id]
if (recId == countByMeta[record.signature]['smallest_id']) {
trClass = 'duplrowkeep'
}
else {
trClass = 'duplrowdel'
}
}
// -------------------------------------------------------------- 8< -------
// pr("\tulWriter: "+record.id) // pr("\tulWriter: "+record.id)
var tr = ''; var tr = '';
var cp_rec = {} var cp_rec = {}
if(!MyTable) { if(!MyTable) {
// £TODO check if ever used
for(var i in record) { for(var i in record) {
cp_rec[i] = transformContent(RecDict[record.id], i , record[i]) cp_rec[i] = transformContent(RecDict[record.id], i , record[i])
} }
} else { } else {
// pr("\t\tbfr transf2: rec_id="+record.id+" | arg="+RecDict[record.id]) // pr("\t\tbfr transf2: rec_id="+record.id+" | arg="+RecDict[record.id])
cp_rec = transformContent2(RecDict[record.id]) cp_rec = transformContent2(RecDict[record.id], trClass)
} }
// grab the record's attribute for each column // grab the record's attribute for each column
for (var i = 0, len = columns.length; i < len; i++) { for (var i = 0, len = columns.length; i < len; i++) {
tr += cellWriter(columns[i], cp_rec); tr += cellWriter(columns[i], cp_rec);
} }
return '<tr>' + tr + '</tr>';
return '<tr class='+trClass+' node-id='+record.id+'>' + tr + '</tr>';
} }
...@@ -330,7 +366,12 @@ function Main_test(Data) { ...@@ -330,7 +366,12 @@ function Main_test(Data) {
div_table += "\t"+"\t"+'<span class="glyphicon glyphicon-star"></span>'+"\n" div_table += "\t"+"\t"+'<span class="glyphicon glyphicon-star"></span>'+"\n"
div_table += "\t"+"\t"+'</th>'+"\n" div_table += "\t"+"\t"+'</th>'+"\n"
div_table += "\t"+"\t"+'<th data-dynatable-column="del" data-dynatable-no-sort="true">'+"\n" div_table += "\t"+"\t"+'<th data-dynatable-column="del" data-dynatable-no-sort="true">'+"\n"
div_table += "\t"+"\t"+'<span class="glyphicon glyphicon-trash"></span>'+"\n" div_table += "\t"+"\t"+'<span class="glyphicon glyphicon-trash" style="padding:3 2 0 0"></span>'+"\n"
div_table += "\t"+"\t"+'<p class="note" style="padding:0 0 1 3">'
div_table += "\t"+"\t"+"\t"+'<input type="checkbox" id="trashAll"'
div_table += "\t"+"\t"+"\t"+' onclick="trashAll(this)" title="Check to mark all for trash"></input>'
div_table += "\t"+"\t"+"\t"+'<label>All page</label>'
div_table += "\t"+"\t"+'</p>'
div_table += "\t"+"\t"+'</th>'+"\n" div_table += "\t"+"\t"+'</th>'+"\n"
div_table += "\t"+'</thead>'+"\n" div_table += "\t"+'</thead>'+"\n"
div_table += "\t"+'<tbody>'+"\n" div_table += "\t"+'<tbody>'+"\n"
...@@ -494,6 +535,7 @@ function Main_test(Data) { ...@@ -494,6 +535,7 @@ function Main_test(Data) {
records: Data, records: Data,
sorts : {"date": 1}, sorts : {"date": 1},
sortTypes: { sortTypes: {
signature: 'signatureSort',
docurl: 'rawtitleSort', docurl: 'rawtitleSort',
'hyperdata.journal': 'journalSort' 'hyperdata.journal': 'journalSort'
} }
...@@ -561,27 +603,24 @@ function Main_test(Data) { ...@@ -561,27 +603,24 @@ function Main_test(Data) {
.functions['docFilter'] = function(record,opt) { .functions['docFilter'] = function(record,opt) {
if (opt == 'filter_all') return true if (opt == 'filter_all') return true
else if (opt == 'filter_favs') return favorites[record.id] else if (opt == 'filter_favs') return favorites[record.id]
else if (opt == 'filter_dupl_tit') return (countByTitles[record.rawtitle] > 1) else if (opt == 'filter_dupl_all') return (countByMeta[record.signature]['n'] > 1)
else if (opt == 'filter_dupl_all') return (countByMeta[record.signature] > 1)
} }
// and set this filter's initial status to 'filter_all' // and set this filter's initial status to 'filter_all'
MyTable.data('dynatable').settings.dataset.queries['docFilter'] = 'filter_all' MyTable.data('dynatable').settings.dataset.queries['docFilter'] = 'filter_all'
MyTable.data('dynatable').sorts.functions["rawtitleSort"] = function rawtitleSort (rec1,rec2, attr, direction) { MyTable.data('dynatable').sorts.functions["rawtitleSort"] = makeAlphaSortFunctionOnProperty('rawtitle')
// sorts on rawtitle instead of derived docurl MyTable.data('dynatable').sorts.functions["signatureSort"] = makeAlphaSortFunctionOnProperty('signature')
// and sorts with locale-aware order
if (direction == 1) return rec1.rawtitle.localeCompare(rec2.rawtitle)
else return rec2.rawtitle.localeCompare(rec1.rawtitle)
}
MyTable.data('dynatable').sorts.functions["journalSort"] = function journalSort (rec1,rec2, attr, direction) { MyTable.data('dynatable').sorts.functions["journalSort"] = function journalSort (rec1,rec2, attr, direction) {
// like rawtitle but nested property // like rawtitle but nested property
if (direction == 1) return rec1.hyperdata.journal.localeCompare(rec2.hyperdata.journal) if (direction == 1) return rec1.hyperdata.journal.localeCompare(rec2.hyperdata.journal)
else return rec2.hyperdata.journal.localeCompare(rec1.hyperdata.journal) else return rec2.hyperdata.journal.localeCompare(rec1.hyperdata.journal)
} }
// hook on page change
MyTable.bind('dynatable:page:set', tidyAfterPageSet)
MyTable.data('dynatable').process(); MyTable.data('dynatable').process();
// re-apply search function on click // re-apply search function on click
...@@ -596,43 +635,114 @@ function Main_test(Data) { ...@@ -596,43 +635,114 @@ function Main_test(Data) {
} }
}) })
// trashAll default position is: off
$('#trashAll').prop("checked", false)
// real trashAll states : SOME|ALL|NONE
$('#trashAll').data("columnSelection", 'SOME')
return "OK" return "OK"
} }
// create a sort function (alphabetic with locale-aware order)
// on any record.property with a str inside (for instance "rawtitle") // select all column "trash"
function makeAlphaSortFunctionOnProperty(property) { // --------------------------
return function (rec1,rec2, attr, direction) { /**
if (direction == 1) return rec1[property].localeCompare(rec2[property]) * Toggle all checkboxes in a column by changing their list in System
else return rec2[property].localeCompare(rec1[property]) *
* effect => sets the "del" property of all visible records on this page
* ------------------
* (except if they are of class duplrowkeep)
* cf more complex original function SelectPage() in NGrams_dyna_chart_and_table
*/
function trashAll() {
var newColumnState = $("#trashAll").prop('checked')
// propagate changes to all rows
$("tbody tr").each(function (i, row) {
// var nodeId = $(row).attr("node-id") ;
// var recId = RecDict[nodeId]
var exceptionUntrashable = row.classList.contains('duplrowkeep')
if (!exceptionUntrashable) {
var boxElem = row.getElementsByClassName("trash1")[0]
var stateBefore = boxElem.checked
if (stateBefore != newColumnState) {
// toggle all these rows' boxes
boxElem.checked = newColumnState
// and trigger the corresponding action manually
toggleTrashIt(boxElem)
} }
} }
});
// OK update this table page
MyTable.data('dynatable').dom.update();
}
// global flag when duplicates special filter is requested
var dupFlag = false ; var dupFlag = false ;
// intercept duplicates query to sort alphabetically **before** duplicates filter
$("#div-table").on("dynatable:queries:added", function(e, qname, qval) { $("#div-table").on("dynatable:queries:added", function(e, qname, qval) {
// debug // debug
// console.warn(e) // console.warn(e)
if (!dupFlag && qname == 'docFilter' && (qval == "filter_dupl_tit" || qval == "filter_dupl_all")) { if (!dupFlag && qname == 'docFilter' && qval == "filter_dupl_all") {
MyTable.data('dynatable').queries.remove('docFilter') MyTable.data('dynatable').queries.remove('docFilter')
// to avoid recursion when we'll call this filter again in 4 lines // flag to avoid recursion when we'll call this filter again in 4 lines
dupFlag = true ; dupFlag = true ;
// sort alphabetically **before** duplicates filter // the sorting
MyTable.data('dynatable').sorts.clear(); MyTable.data('dynatable').sorts.clear();
MyTable.data('dynatable').sorts.add('rawtitle', -1) // -1 <==> DESC (ASC doesn't work well ?) MyTable.data('dynatable').sorts.add('docurl', 1)
// now we can add the query
MyTable.data('dynatable').queries.add('docFilter', qval) MyTable.data('dynatable').queries.add('docFilter', qval)
MyTable.data('dynatable').process(); MyTable.data('dynatable').process();
} }
else if (qname == 'docFilter') {
dupFlag = false
}
}); });
$("#div-table").on("dynatable:queries:removed", function(e, qname) { $("#div-table").on("dynatable:queries:removed", function(e, qname, qval) {
if (qname == 'docFilter') { if (qname == 'filter_dupl_all') {
dupFlag = false ; dupFlag = false ;
} }
}); });
// create a sort function (alphabetic with locale-aware order)
// on any record.property with a str inside (for instance "rawtitle")
function makeAlphaSortFunctionOnProperty(property) {
return function (rec1,rec2, attr, direction) {
var cmp = null
// the alphabetic sort
if (direction == 1) cmp = rec1[property].localeCompare(rec2[property])
else cmp = rec2[property].localeCompare(rec1[property])
// second level sorting on key = id in records array
// (this one volontarily not reversable by direction
// so as to have smallest_id always on top in layout)
if (cmp == 0) cmp = RecDict[rec1.id] < RecDict[rec2.id] ? -1 : 1
return cmp
}
}
/**
* tidyAfterPageSet:
* -------------
* Here we clean vars that become obsolete not at all updates, but only
* when page changes (bound to the dynatable event "dynatable:page:set")
*/
function tidyAfterPageSet() {
// we visually uncheck the 'trashAll' box
$('input#trashAll').attr('checked', false);
}
// FIRST portion of code to be EXECUTED: // FIRST portion of code to be EXECUTED:
// (3) Get records and hyperdata for paginator // (3) Get records and hyperdata for paginator
$.ajax({ $.ajax({
...@@ -682,10 +792,20 @@ $.ajax({ ...@@ -682,10 +792,20 @@ $.ajax({
ourSignature = metaSignature(rec) ourSignature = metaSignature(rec)
if (countByMeta.hasOwnProperty(ourSignature)) { if (countByMeta.hasOwnProperty(ourSignature)) {
countByMeta[ourSignature] ++ ;
// property n contains the count
countByMeta[ourSignature]['n'] ++ ;
// no need to check for min rec_id b/c loop in ascending order
} }
else { else {
countByMeta[ourSignature] = 1 ; countByMeta[ourSignature] = {'n':undefined,
'smallest_id':undefined}
countByMeta[ourSignature]['n'] = 1 ;
// we also take the min rec_id
// (to keep only one exemplar at deduplication)
countByMeta[ourSignature]['smallest_id'] = i ;
} }
// also save record's "meta signature" for later lookup // also save record's "meta signature" for later lookup
rec.signature = ourSignature rec.signature = ourSignature
......
...@@ -46,6 +46,25 @@ th a { ...@@ -46,6 +46,25 @@ th a {
} }
/* special effects for duplicate rows
*
* NB: top/bottom convention only works because of sort rule that always put smallest id first
*/
.duplrowkeep {
border-top: 3px solid black
}
.duplrowdel {
background-color: #CCC;
border-bottom: 3px solid black
}
/* table titles */
th.dynatable-head {
vertical-align: middle !important;
}
/* notes under table titles */ /* notes under table titles */
th .note { th .note {
color: #ccc; color: #ccc;
...@@ -77,6 +96,8 @@ p.note > input { ...@@ -77,6 +96,8 @@ p.note > input {
p.note > label { p.note > label {
float: left; float: left;
margin-bottom: 0 ;
padding-bottom: 0 ;
} }
.smaller { .smaller {
...@@ -89,7 +110,7 @@ p.note > label { ...@@ -89,7 +110,7 @@ p.note > label {
#my-ajax-table tr:hover { #my-ajax-table tr:hover {
cursor: pointer; cursor: pointer;
font-weight: bold; /*font-weight: bold;*/
} }
/* ngram states */ /* ngram states */
......
...@@ -76,7 +76,6 @@ ...@@ -76,7 +76,6 @@
<select id="docFilter" name="docFilter"> <select id="docFilter" name="docFilter">
<option value="filter_all">All</option> <option value="filter_all">All</option>
<option value="filter_favs">Favorite documents</option> <option value="filter_favs">Favorite documents</option>
<option value="filter_dupl_tit">Duplicates (title)</option>
<option value="filter_dupl_all">Duplicates (title, date &amp; src)</option> <option value="filter_dupl_all">Duplicates (title, date &amp; src)</option>
</select> </select>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment