diff --git a/doajtest/testbook/public_site/subject_facet.yml b/doajtest/testbook/public_site/subject_facet.yml
index 6a36629566..a5dece6f88 100644
--- a/doajtest/testbook/public_site/subject_facet.yml
+++ b/doajtest/testbook/public_site/subject_facet.yml
@@ -102,7 +102,7 @@ tests:
Chemical Technology)
results:
- The subject and any parents are selected in the facet
- - The search box clears
+ - The facet status hasn't changed - the search query is still visible in the search box and the tree is filtered
- step: Enter another search of 3 or more characters, which will also return the
values you selected in the previous step (e.g. "Bio")
results:
@@ -113,14 +113,17 @@ tests:
- step: Select another subject from another part of the tree (e.g. Medicine)
results:
- All your subjects and any parents are selected in the facet
- - The search box clears
+ - The facet status hasn't changed - the last search query is displayed in the input field and the tree is filtered
- step: Enter your second search again (e.g. "Bio")
- step: Unselect one of the subjects you had previously selected (e.g. Chemical
Technology)
results:
- Your second subject is still present (e.g. Medicine) and any parents of the
subject you unselected are still present (e.g. Technology)
- - The search box clears
+ - The facet status hasn't changed - the last search query is displayed in the input field and the tree is filtered
- step: Enter a long random string into the search box
results:
- A message is displayed "No subjects match your search"
+ - step: Remove a string from the search box
+ results:
+ - The facet shows all subjects with all levels folded
diff --git a/portality/static/js/doaj.fieldrender.edges.js b/portality/static/js/doaj.fieldrender.edges.js
index dc3138e4f8..09d172346d 100644
--- a/portality/static/js/doaj.fieldrender.edges.js
+++ b/portality/static/js/doaj.fieldrender.edges.js
@@ -1,6 +1,6 @@
$.extend(true, doaj, {
- filters : {
- noCharges : function() {
+ filters: {
+ noCharges: function () {
return {
id: "no_charges",
display: "Without fees",
@@ -17,26 +17,26 @@ $.extend(true, doaj, {
}
}
},
- facets : {
- inDOAJ : function() {
+ facets: {
+ inDOAJ: function () {
return edges.newRefiningANDTermSelector({
id: "in_doaj",
category: "facet",
field: "admin.in_doaj",
display: "In DOAJ?",
deactivateThreshold: 1,
- valueMap : {
- 1 : "Yes",
- 0 : "No",
+ valueMap: {
+ 1: "Yes",
+ 0: "No",
true: "Yes",
false: "No"
},
- parseSelectedValueString: function(val) {
+ parseSelectedValueString: function (val) {
// this is needed because ES7 doesn't understand "1" or `1` to be `true`, so
// we convert the string value of the aggregation back to a boolean
return val === "1"
},
- filterToAggValue : function(val) {
+ filterToAggValue: function (val) {
return val === true ? 1 : 0;
},
renderer: edges.bs3.newRefiningANDTermSelectorRenderer({
@@ -49,15 +49,15 @@ $.extend(true, doaj, {
})
},
- openOrClosed: function() {
+ openOrClosed: function () {
return edges.newRefiningANDTermSelector({
id: "application_type",
category: "facet",
field: "index.application_type.exact",
display: "Open or closed?",
- deactivateThreshold : 1,
+ deactivateThreshold: 1,
orderDir: "asc",
- valueMap : {
+ valueMap: {
"finished application/update": "Closed",
"update request": "Open",
"new application": "Open"
@@ -72,7 +72,7 @@ $.extend(true, doaj, {
})
},
- applicationStatus : function() {
+ applicationStatus: function () {
return edges.newRefiningANDTermSelector({
id: "application_status",
category: "facet",
@@ -89,13 +89,13 @@ $.extend(true, doaj, {
})
})
},
- hasEditorGroup : function() {
+ hasEditorGroup: function () {
return edges.newRefiningANDTermSelector({
id: "has_editor_group",
category: "facet",
field: "index.has_editor_group.exact",
display: "Has editor group?",
- deactivateThreshold : 1,
+ deactivateThreshold: 1,
renderer: edges.bs3.newRefiningANDTermSelectorRenderer({
controls: true,
open: false,
@@ -105,7 +105,7 @@ $.extend(true, doaj, {
})
})
},
- hasEditor : function() {
+ hasEditor: function () {
return edges.newRefiningANDTermSelector({
id: "has_editor",
category: "facet",
@@ -121,7 +121,7 @@ $.extend(true, doaj, {
})
})
},
- editorGroup : function() {
+ editorGroup: function () {
return edges.newRefiningANDTermSelector({
id: "editor_group",
category: "facet",
@@ -137,7 +137,7 @@ $.extend(true, doaj, {
})
})
},
- editor : function() {
+ editor: function () {
return edges.newRefiningANDTermSelector({
id: "editor",
category: "facet",
@@ -153,7 +153,7 @@ $.extend(true, doaj, {
})
})
},
- hasAPC : function() {
+ hasAPC: function () {
return edges.newRefiningANDTermSelector({
id: "author_pays",
category: "facet",
@@ -169,7 +169,7 @@ $.extend(true, doaj, {
})
})
},
- classification : function() {
+ classification: function () {
return edges.newRefiningANDTermSelector({
id: "classification",
category: "facet",
@@ -185,7 +185,7 @@ $.extend(true, doaj, {
})
})
},
- language : function() {
+ language: function () {
return edges.newRefiningANDTermSelector({
id: "language",
category: "facet",
@@ -201,7 +201,7 @@ $.extend(true, doaj, {
})
})
},
- countryPublisher : function() {
+ countryPublisher: function () {
return edges.newRefiningANDTermSelector({
id: "country_publisher",
category: "facet",
@@ -217,7 +217,7 @@ $.extend(true, doaj, {
})
})
},
- subject : function() {
+ subject: function () {
return edges.newRefiningANDTermSelector({
id: "subject",
category: "facet",
@@ -233,7 +233,7 @@ $.extend(true, doaj, {
})
})
},
- publisher : function() {
+ publisher: function () {
return edges.newRefiningANDTermSelector({
id: "publisher",
category: "facet",
@@ -249,7 +249,7 @@ $.extend(true, doaj, {
})
})
},
- journalLicence : function() {
+ journalLicence: function () {
return edges.newRefiningANDTermSelector({
id: "journal_license",
category: "facet",
@@ -267,29 +267,29 @@ $.extend(true, doaj, {
}
},
- valueMaps : {
+ valueMaps: {
// This must be updated in line with the list in formcontext/choices.py
- applicationStatus : {
- 'update_request' : 'Update Request',
- 'revisions_required' : 'Revisions Required',
- 'pending' : 'Pending',
- 'in progress' : 'In Progress',
- 'completed' : 'Completed',
- 'on hold' : 'On Hold',
- 'ready' : 'Ready',
- 'rejected' : 'Rejected',
- 'accepted' : 'Accepted',
+ applicationStatus: {
+ 'update_request': 'Update Request',
+ 'revisions_required': 'Revisions Required',
+ 'pending': 'Pending',
+ 'in progress': 'In Progress',
+ 'completed': 'Completed',
+ 'on hold': 'On Hold',
+ 'ready': 'Ready',
+ 'rejected': 'Rejected',
+ 'accepted': 'Accepted',
'post_submission_review': "Autochecking",
},
- adminStatusMap: function(value) {
+ adminStatusMap: function (value) {
if (doaj.valueMaps.applicationStatus.hasOwnProperty(value)) {
return doaj.valueMaps.applicationStatus[value];
}
return value;
},
- displayYearPeriod : function(params) {
+ displayYearPeriod: function (params) {
var from = params.from;
var to = params.to;
var field = params.field;
@@ -297,7 +297,7 @@ $.extend(true, doaj, {
return {to: to, toType: "lt", from: from, fromType: "gte", display: display}
},
- displayYearMonthPeriod : function(params) {
+ displayYearMonthPeriod: function (params) {
var from = params.from;
var to = params.to;
var field = params.field;
@@ -307,8 +307,9 @@ $.extend(true, doaj, {
return {to: to, toType: "lt", from: from, fromType: "gte", display: display}
},
- schemaCodeToNameClosure : function(tree) {
+ schemaCodeToNameClosure: function (tree) {
var nameMap = {};
+
function recurse(ctx) {
for (var i = 0; i < ctx.length; i++) {
var child = ctx[i];
@@ -319,9 +320,10 @@ $.extend(true, doaj, {
}
}
}
+
recurse(tree);
- return function(code) {
+ return function (code) {
var name = nameMap[code];
if (name) {
return name;
@@ -330,7 +332,7 @@ $.extend(true, doaj, {
}
},
- countFormat : edges.numFormat({
+ countFormat: edges.numFormat({
thousandsSeparator: ","
}),
@@ -338,8 +340,8 @@ $.extend(true, doaj, {
zeroPadding: 2
})
},
- components : {
- pager : function(id, category) {
+ components: {
+ pager: function (id, category) {
return edges.newPager({
id: id,
category: category,
@@ -351,18 +353,18 @@ $.extend(true, doaj, {
})
},
- searchingNotification : function() {
+ searchingNotification: function () {
return edges.newSearchingNotification({
id: "searching-notification",
category: "searching-notification",
finishedEvent: "edges:post-render",
- renderer : doaj.renderers.newSearchingNotificationRenderer({
+ renderer: doaj.renderers.newSearchingNotificationRenderer({
scrollOnSearch: true
})
})
},
- subjectBrowser : function(params) {
+ subjectBrowser: function (params) {
var tree = params.tree;
var hideEmpty = edges.getParam(params.hideEmpty, false);
@@ -370,7 +372,7 @@ $.extend(true, doaj, {
id: "subject",
category: "facet",
field: "index.schema_codes_tree.exact",
- tree: function(tree) {
+ tree: function (tree) {
function recurse(ctx) {
var displayTree = [];
for (var i = 0; i < ctx.length; i++) {
@@ -386,11 +388,12 @@ $.extend(true, doaj, {
displayTree.sort((a, b) => a.display > b.display ? 1 : -1);
return displayTree;
}
+
return recurse(tree);
}(tree),
pruneTree: true,
size: 9999,
- nodeMatch: function(node, match_list) {
+ nodeMatch: function (node, match_list) {
for (var i = 0; i < match_list.length; i++) {
var m = match_list[i];
if (node.value === m.key) {
@@ -399,10 +402,10 @@ $.extend(true, doaj, {
}
return -1;
},
- filterMatch: function(node, selected) {
+ filterMatch: function (node, selected) {
return $.inArray(node.value, selected) > -1;
},
- nodeIndex : function(node) {
+ nodeIndex: function (node) {
return node.display.toLowerCase();
},
renderer: doaj.renderers.newSubjectBrowser({
@@ -415,7 +418,7 @@ $.extend(true, doaj, {
}
},
- templates : {
+ templates: {
newPublicSearch: function (params) {
return edges.instantiate(doaj.templates.PublicSearch, params, edges.newTemplate);
},
@@ -543,7 +546,7 @@ $.extend(true, doaj, {
}
},
- renderers : {
+ renderers: {
newSearchingNotificationRenderer: function (params) {
return edges.instantiate(doaj.renderers.SearchingNotificationRenderer, params, edges.newRenderer);
},
@@ -584,7 +587,7 @@ $.extend(true, doaj, {
},
{
duration: 1000,
- always: function() {
+ always: function () {
$(idSelector).remove();
}
}
@@ -593,10 +596,10 @@ $.extend(true, doaj, {
}
},
- newSubjectBrowser : function(params) {
+ newSubjectBrowser: function (params) {
return edges.instantiate(doaj.renderers.SubjectBrowser, params, edges.newRenderer);
},
- SubjectBrowser : function(params) {
+ SubjectBrowser: function (params) {
this.title = edges.getParam(params.title, "");
this.selectMode = edges.getParam(params.selectMode, "multiple");
@@ -611,9 +614,17 @@ $.extend(true, doaj, {
this.namespace = "doaj-subject-browser";
+ this.viewWindowScrollOffset = 0;
this.lastScroll = 0;
+ this.lastSearch = edges.getParam(params.lastSearch, null);
+ this.lastClickedEl = edges.getParam(params.lastClickedEl, null);
+
+ this.init = function(component) {
+ edges.newRenderer().init.call(this, component);
+ component.edge.context.on("edges:pre-reset", edges.eventClosure(this, "reset"));
+ }
- this.draw = function() {
+ this.draw = function () {
// for convenient short references ...
var st = this.component.syncTree;
var namespace = this.namespace;
@@ -643,7 +654,12 @@ $.extend(true, doaj, {
var frag = '
\
\
\
-
\
+
\
\
\
';
@@ -655,11 +671,19 @@ $.extend(true, doaj, {
this.component.context.html(frag);
feather.replace();
+ if (this.lastSearch) {
+ var searchSelector = edges.css_id_selector(namespace, "search", this);
+ this.filterSubjects($(searchSelector));
+ }
+
+
// trigger all the post-render set-up functions
this.setUIOpen();
var mainListSelector = edges.css_id_selector(namespace, "main", this);
- this.component.jq(mainListSelector).scrollTop(this.lastScroll);
+ var filterSelector = edges.css_id_selector(this.namespace, "filtered", this);
+ var selector = this.lastSearch ? filterSelector : mainListSelector;
+ this.component.jq(selector).scrollTop(this.lastScroll);
var checkboxSelector = edges.css_class_selector(namespace, "selector", this);
edges.on(checkboxSelector, "change", this, "filterToggle");
@@ -671,7 +695,14 @@ $.extend(true, doaj, {
edges.on(searchSelector, "keyup", this, "filterSubjects");
};
- this._renderTree = function(params) {
+ this.reset = function(edge) {
+ this.lastSearch = null;
+ this.viewWindowScrollOffset = 0;
+ this.lastClickedEl = null;
+ this.lastScroll = 0;
+ }
+
+ this._renderTree = function (params) {
var st = edges.getParam(params.tree, []);
var selectedPathOnly = edges.getParam(params.selectedPathOnly, true);
var showOneLevel = edges.getParam(params.showOneLevel, true);
@@ -759,7 +790,7 @@ $.extend(true, doaj, {
rFrag += entryFrag;
rFrag += '';
}
- return {frag : rFrag, anySelected: anySelected};
+ return {frag: rFrag, anySelected: anySelected};
}
return recurse(st);
@@ -777,17 +808,20 @@ $.extend(true, doaj, {
results.addClass("in").attr("aria-expanded", "true").css({"height": ""});
toggle.removeClass("collapsed").attr("aria-expanded", "true");
} else {
- results.removeClass("in").attr("aria-expanded", "false").css({"height" : "0px"});
+ results.removeClass("in").attr("aria-expanded", "false").css({"height": "0px"});
toggle.addClass("collapsed").attr("aria-expanded", "false");
}
};
- this.filterToggle = function(element) {
+ this.filterToggle = function (element) {
var mainListSelector = edges.css_id_selector(this.namespace, "main", this);
- this.lastScroll = this.component.jq(mainListSelector).scrollTop();
+ var filterSelector = edges.css_id_selector(this.namespace, "filtered", this);
+ this.lastScroll = this.lastSearch ? this.component.jq(filterSelector).scrollTop() : this.component.jq(mainListSelector).scrollTop();
var el = this.component.jq(element);
- // var filter_id = this.component.jq(element).attr("id");
var checked = el.is(":checked");
+ this.lastClickedEl = el[0].id;
+ let offset = this.lastSearch ? this.component.jq(filterSelector).offset().top : this.component.jq(mainListSelector).offset().top;
+ this.viewWindowScrollOffset = el.offset().top - offset;
var value = el.attr("data-value");
if (checked) {
this.component.addFilter({value: value});
@@ -801,7 +835,47 @@ $.extend(true, doaj, {
this.setUIOpen();
};
- this.filterSubjects = function(element) {
+ this._findParentObject = function(st, value) {
+ // Iterate through the array to find the object with children containing the lastClickedEl value
+ for (const obj of st) {
+ if (obj.children && obj.children.some(child => child.value === value)) {
+ return obj;
+ }
+ }
+ return null; // If no parent object is found
+ }
+
+ this._findRenderedElement = function(st, value) {
+ // Step 1: Find HTML element with id=lastClickedEl
+ const element = document.getElementById(value);
+
+ // Step 2: If it exists, return the element
+ if (element) {
+ return element;
+ }
+
+ // Step 3: If it doesn't exist, find the parent in the st array
+ const parentObject = this._findParentObject(st, value);
+
+ // Step 4: If no more parents (no elements found), return null
+ if (!parentObject) {
+ return null;
+ }
+
+ // Step 5: Repeat this algorithm for the value of the found parent
+ return this._findRenderedElement(st, parentObject.value);
+ }
+
+ this.scrollView = function (view) {
+ var browser = view[0];
+ var st = this.component.syncTree;
+ var elemToScroll = this._findRenderedElement(st, this.lastClickedEl);
+ if (elemToScroll) {
+ browser.scrollTop = elemToScroll.offsetTop - browser.offsetTop - this.viewWindowScrollOffset;
+ }
+ }
+
+ this.filterSubjects = function (element) {
var st = this.component.syncTree;
var term = $(element).val();
var that = this;
@@ -815,6 +889,10 @@ $.extend(true, doaj, {
filterEl.html("");
filterEl.hide();
mainEl.show();
+ this.lastSearch = null;
+ if (this.lastClickedEl) {
+ this.scrollView(mainEl);
+ }
return;
}
if (term.length < 3) {
@@ -823,6 +901,7 @@ $.extend(true, doaj, {
mainEl.hide();
return;
}
+ this.lastSearch = term;
term = term.toLowerCase();
function entryMatch(entry) {
@@ -831,7 +910,7 @@ $.extend(true, doaj, {
}
var matchTerm = entry.index;
- var includes = matchTerm.includes(term);
+ var includes = matchTerm.includes(term);
if (includes) {
var idx = matchTerm.indexOf(term);
var display = entry.display;
@@ -866,12 +945,20 @@ $.extend(true, doaj, {
var filtered = recurse(st);
if (filtered.length > 0) {
- var displayReport = this._renderTree({tree: filtered, selectedPathOnly: false, showOneLevel: false});
+ var displayReport = this._renderTree({
+ tree: filtered,
+ selectedPathOnly: false,
+ showOneLevel: false
+ });
filterEl.html(displayReport.frag);
mainEl.hide();
filterEl.show();
+ if (this.lastClickedEl) {
+ this.scrollView(filterEl);
+ }
+
var checkboxSelector = edges.css_class_selector(this.namespace, "selector", this);
edges.on(checkboxSelector, "change", this, "filterToggle");
} else {
@@ -1352,7 +1439,7 @@ $.extend(true, doaj, {
//////////////////////////////////////////////////////
// functions for setting UI values
- this.toggleShare = function(element) {
+ this.toggleShare = function (element) {
var shareUrlSelector = edges.css_class_selector(this.namespace, "share-url", this);
var textarea = this.component.jq(shareUrlSelector);
@@ -1368,7 +1455,7 @@ $.extend(true, doaj, {
}
};
- this.toggleShorten = function(element) {
+ this.toggleShorten = function (element) {
if (!this.component.shortUrl) {
var callback = edges.objClosure(this, "updateShortUrl");
this.component.generateShortUrl(callback);
@@ -1377,7 +1464,7 @@ $.extend(true, doaj, {
}
};
- this.updateShortUrl = function() {
+ this.updateShortUrl = function () {
var shareUrlSelector = edges.css_class_selector(this.namespace, "share-url", this);
var shortenSelector = edges.css_class_selector(this.namespace, "shorten-url", this);
var textarea = this.component.jq(shareUrlSelector);
@@ -1678,7 +1765,7 @@ $.extend(true, doaj, {
}
};
- this.filterToggle = function(element) {
+ this.filterToggle = function (element) {
var filter_id = this.component.jq(element).attr("id");
var checked = this.component.jq(element).is(":checked");
if (checked) {
@@ -1892,12 +1979,12 @@ $.extend(true, doaj, {
//}
//results.hide();
- results.removeClass("in").attr("aria-expanded", "false").css({"height" : "0px"});
+ results.removeClass("in").attr("aria-expanded", "false").css({"height": "0px"});
toggle.addClass("collapsed").attr("aria-expanded", "false");
}
};
- this.filterToggle = function(element) {
+ this.filterToggle = function (element) {
var term = this.component.jq(element).attr("data-key");
var checked = this.component.jq(element).is(":checked");
if (checked) {
@@ -2154,7 +2241,7 @@ $.extend(true, doaj, {
//}
//results.hide();
- results.removeClass("in").attr("aria-expanded", "false").css({"height" : "0px"});
+ results.removeClass("in").attr("aria-expanded", "false").css({"height": "0px"});
toggle.addClass("collapsed").attr("aria-expanded", "false");
}
};
@@ -2162,7 +2249,7 @@ $.extend(true, doaj, {
/////////////////////////////////////////////////////
// event handlers
- this.filterToggle = function(element) {
+ this.filterToggle = function (element) {
var gte = this.component.jq(element).attr("data-gte");
var lt = this.component.jq(element).attr("data-lt");
var checked = this.component.jq(element).is(":checked");
@@ -2375,7 +2462,7 @@ $.extend(true, doaj, {
this.component.removeFilter(bool, ft, field, value);
};
- this.clearFilters = function() {
+ this.clearFilters = function () {
this.component.clearSearch();
}
},
@@ -2455,16 +2542,15 @@ $.extend(true, doaj, {
};
},
- newPublicSearchResultRenderer : function(params) {
+ newPublicSearchResultRenderer: function (params) {
return edges.instantiate(doaj.renderers.PublicSearchResultRenderer, params, edges.newRenderer);
},
- PublicSearchResultRenderer : function(params) {
+ PublicSearchResultRenderer: function (params) {
this.widget = params.widget;
if (params.doaj_url) {
this.doaj_url = params.doaj_url;
- }
- else {
+ } else {
this.doaj_url = ""
}
@@ -2473,11 +2559,11 @@ $.extend(true, doaj, {
this.namespace = "doaj-public-search";
this.selector = edges.getParam(params.selector, null)
- this.currentQueryString = "";
+ this.currentQueryString = "";
this.draw = function () {
- if (this.component.edge.currentQuery){
+ if (this.component.edge.currentQuery) {
let qs = this.component.edge.currentQuery.getQueryString();
if (qs) {
this.currentQueryString = qs.queryString || "";
@@ -2515,7 +2601,7 @@ $.extend(true, doaj, {
edges.on(abstractAction, "click", this, "toggleAbstract");
};
- this.toggleAbstract = function(element) {
+ this.toggleAbstract = function (element) {
var el = $(element);
var abstractText = edges.css_class_selector(this.namespace, "abstracttext", this);
var at = this.component.jq(abstractText).filter('[rel="' + el.attr("rel") + '"]');
@@ -2529,7 +2615,7 @@ $.extend(true, doaj, {
}
};
- this._renderResult = function(resultobj) {
+ this._renderResult = function (resultobj) {
if (resultobj.bibjson && resultobj.bibjson.journal) {
// it is an article
return this._renderPublicArticle(resultobj);
@@ -2539,15 +2625,14 @@ $.extend(true, doaj, {
}
};
- this._renderPublicJournal = function(resultobj) {
+ this._renderPublicJournal = function (resultobj) {
var seal = "";
if (edges.objVal("admin.seal", resultobj, false)) {
seal = ''
- if (this.widget){
+ if (this.widget) {
seal += ' DOAJ Seal'
- }
- else {
+ } else {
seal += '