Skip to content

Commit 21c4cde

Browse files
committed
Update "Select All" in nav tree
1 parent 140af0a commit 21c4cde

File tree

4 files changed

+112
-39
lines changed

4 files changed

+112
-39
lines changed

api/src/org/labkey/api/data/DataRegion.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,8 @@ private HtmlWriter renderNavTree(HtmlWriter out)
15581558
final String jsObject = getJavaScriptObjectReference();
15591559
NavTree navtree = new NavTree();
15601560

1561-
NavTree selectAll = new NavTree("Select All");
1561+
NavTree selectAll = new NavTree("Select All Rows");
1562+
selectAll.setId(getDomId() + "-navtree-select-all");
15621563
selectAll.setScript(jsObject + ".selectAll();");
15631564
navtree.addChild(selectAll);
15641565

api/src/org/labkey/api/data/DataRegionSelection.java

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -267,29 +267,48 @@ public static int setSelected(ViewContext context, String key, Collection<String
267267
* Sets the checked state for the given ids in the session state.
268268
*/
269269
public static int setSelected(ViewContext context, String key, Collection<String> selection, boolean checked, boolean useSnapshot)
270+
{
271+
return setSelected(context, key, selection, checked, useSnapshot, false);
272+
}
273+
274+
private static int setSelected(
275+
ViewContext context,
276+
String key,
277+
Collection<String> selection,
278+
boolean checked,
279+
boolean useSnapshot,
280+
boolean replaceSelection
281+
)
270282
{
271283
if (checked && selection.size() > MAX_QUERY_SELECTION_SIZE)
272284
throw new BadRequestException(selectionTooLargeMessage(selection.size()));
273285

274286
Set<String> selectedValues = getSet(context, key, true, useSnapshot);
275287
if (checked)
276288
{
277-
// Verify that adding these selections will not result in a set that is too large
278-
if (selectedValues.size() + selection.size() > MAX_QUERY_SELECTION_SIZE)
289+
synchronized (selectedValues)
279290
{
280-
// Do not modify the actual selected values
281-
int current = selectedValues.size();
282-
int distinctAdds = 0;
283-
284-
for (String id : selection)
291+
if (replaceSelection)
285292
{
286-
if (!selectedValues.contains(id))
287-
distinctAdds++;
293+
selectedValues.clear();
288294
}
295+
else if (selectedValues.size() + selection.size() > MAX_QUERY_SELECTION_SIZE)
296+
{
297+
// Verify that adding these selections will not result in a set that is too large
298+
// Do not modify the actual selected values yet
299+
int current = selectedValues.size();
300+
int distinctAdds = 0;
289301

290-
int prospective = current + distinctAdds;
291-
if (prospective > MAX_QUERY_SELECTION_SIZE)
292-
throw new BadRequestException(selectionTooLargeMessage(prospective));
302+
for (String id : selection)
303+
{
304+
if (!selectedValues.contains(id))
305+
distinctAdds++;
306+
}
307+
308+
int prospective = current + distinctAdds;
309+
if (prospective > MAX_QUERY_SELECTION_SIZE)
310+
throw new BadRequestException(selectionTooLargeMessage(prospective));
311+
}
293312
}
294313

295314
selectedValues.addAll(selection);
@@ -387,7 +406,6 @@ public static Set<String> getSelected(QueryForm form, boolean clearSelected) thr
387406

388407
if (clearSelected && !selection.isEmpty())
389408
{
390-
//noinspection SynchronizationOnLocalVariableOrMethodParameter
391409
synchronized (selection)
392410
{
393411
items.forEach(selection::remove);
@@ -486,7 +504,7 @@ public static int setSelectionForAll(QueryView view, String key, boolean checked
486504
try (Timing ignored = MiniProfiler.step("selectAll"); ResultSet rs = rgn.getResults(rc))
487505
{
488506
var selection = createSelectionSet(rc, rgn, rs, null);
489-
return setSelected(view.getViewContext(), key, selection, checked);
507+
return setSelected(view.getViewContext(), key, selection, checked, false, true);
490508
}
491509
catch (SQLException e)
492510
{

api/src/org/labkey/api/view/NavTree.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,13 @@ public LinkBuilder toLinkBuilder(@Nullable String cls)
755755
}
756756
}
757757

758+
String id = getId();
759+
if (id == null)
760+
id = config.makeId("popupMenuView");
761+
id = id.replaceAll(" ", "");
762+
758763
LinkBuilder builder = LinkBuilder.simpleLink(html)
759-
.id(config.makeId("popupMenuView"))
764+
.id(id)
760765
.target(getTarget())
761766
.title(getDescription())
762767
.tabindex(0)

api/webapp/clientapi/dom/DataRegion.js

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ if (!LABKEY.DataRegions) {
1616
var ALL_ROWS_MAX = 5_000;
1717
var CUSTOM_VIEW_PANELID = '~~customizeView~~';
1818
var DEFAULT_TIMEOUT = 30_000;
19-
const MAX_SELECTION_SIZE = LABKEY.moduleContext.query.maxQuerySelection;
19+
const MAX_SELECTION_SIZE = LABKEY.moduleContext.query?.maxQuerySelection ?? 100_000;
2020
var PARAM_PREFIX = '.param.';
2121
var SORT_ASC = '+';
2222
var SORT_DESC = '-';
@@ -852,6 +852,10 @@ if (!LABKEY.DataRegions) {
852852
if (!_selDocClick) {
853853
_selDocClick = $(document).on('click', _onDocumentClick);
854854
}
855+
856+
if (_isShowSelectAll(this)) {
857+
_getNavTreeSelectAllSelector(this).html(_getSelectAllText(this));
858+
}
855859
};
856860

857861
var _selClickLock; // lock to prevent removing a row highlight that was just applied
@@ -911,10 +915,10 @@ if (!LABKEY.DataRegions) {
911915
LABKEY.DataRegion.clearSelected(config);
912916
}
913917

914-
if (this.showRows == 'selected') {
918+
if (this.showRows === 'selected') {
915919
_removeParameters(this, [SHOW_ROWS_PREFIX]);
916920
}
917-
else if (this.showRows == 'unselected') {
921+
else if (this.showRows === 'unselected') {
918922
// keep "SHOW_ROWS_PREFIX=unselected" parameter
919923
window.location.reload(true);
920924
}
@@ -1036,16 +1040,26 @@ if (!LABKEY.DataRegions) {
10361040

10371041
LABKEY.DataRegion.selectAll(config);
10381042

1039-
if (this.showRows === "selected") {
1043+
if (this.showRows === 'selected') {
10401044
// keep "SHOW_ROWS_PREFIX=selected" parameter
10411045
window.location.reload(true);
10421046
}
1043-
else if (this.showRows === "unselected") {
1047+
else if (this.showRows === 'unselected') {
10441048
_removeParameters(this, [SHOW_ROWS_PREFIX]);
10451049
}
1046-
else {
1050+
else if (this.totalRows <= MAX_SELECTION_SIZE) {
10471051
_toggleAllRows(this, true);
10481052
}
1053+
else {
1054+
const lastRowIdx = this.offset + this.rowCount;
1055+
if (lastRowIdx < MAX_SELECTION_SIZE) {
1056+
_toggleAllRows(this, true);
1057+
} else if (this.offset < MAX_SELECTION_SIZE && MAX_SELECTION_SIZE < lastRowIdx) {
1058+
_checkRows(this, MAX_SELECTION_SIZE - this.offset);
1059+
} else {
1060+
_toggleAllRows(this, false);
1061+
}
1062+
}
10491063
}
10501064
};
10511065

@@ -1080,15 +1094,15 @@ if (!LABKEY.DataRegions) {
10801094
var msg;
10811095
if (me.totalRows) {
10821096
if (count == me.totalRows) {
1083-
msg = 'All <span class="labkey-strong">' + this.totalRows + '</span> rows selected.';
1097+
msg = 'All <span class="labkey-strong">' + this.totalRows.toLocaleString() + '</span> rows selected.';
10841098
}
10851099
else {
1086-
msg = 'Selected <span class="labkey-strong">' + count + '</span> of ' + this.totalRows + ' rows.';
1100+
msg = 'Selected <span class="labkey-strong">' + count.toLocaleString() + '</span> of ' + this.totalRows.toLocaleString() + ' rows.';
10871101
}
10881102
}
10891103
else {
10901104
// totalRows isn't available when showing all rows.
1091-
msg = 'Selected <span class="labkey-strong">' + count + '</span> rows.';
1105+
msg = 'Selected <span class="labkey-strong">' + count.toLocaleString() + '</span> rows.';
10921106
}
10931107
_showSelectMessage(me, msg);
10941108
}
@@ -3153,43 +3167,49 @@ if (!LABKEY.DataRegions) {
31533167
return exists;
31543168
};
31553169

3170+
var _getDomIdSelector = function(region, suffix) {
3171+
let selector = '#' + region.domId;
3172+
if (suffix) selector += suffix;
3173+
return $(selector);
3174+
};
3175+
31563176
var _getAllRowSelectors = function(region) {
31573177
return _getFormSelector(region).find('.labkey-selectors input[type="checkbox"][name=".toggle"]');
31583178
};
31593179

31603180
var _getBarSelector = function(region) {
3161-
return $('#' + region.domId + '-headerbar');
3181+
return _getDomIdSelector(region, '-headerbar');
31623182
};
31633183

31643184
var _getContextBarSelector = function(region) {
3165-
return $('#' + region.domId + '-ctxbar');
3185+
return _getDomIdSelector(region, '-ctxbar');
31663186
};
31673187

31683188
var _getDrawerSelector = function(region) {
3169-
return $('#' + region.domId + '-drawer');
3189+
return _getDomIdSelector(region, '-drawer');
31703190
};
31713191

31723192
var _getFormSelector = function(region) {
31733193
var form = $('form#' + region.domId + '-form');
31743194

31753195
// derived DataRegion's may not include the form id
31763196
if (form.length === 0) {
3177-
form = $('#' + region.domId).closest('form');
3197+
form = _getDomIdSelector(region).closest('form');
31783198
}
31793199

31803200
return form;
31813201
};
31823202

31833203
var _getHeaderSelector = function(region) {
3184-
return $('#' + region.domId + '-header');
3204+
return _getDomIdSelector(region, '-header');
31853205
};
31863206

31873207
var _getRowSelectors = function(region) {
31883208
return _getFormSelector(region).find('.labkey-selectors input[type="checkbox"][name=".select"]');
31893209
};
31903210

31913211
var _getSectionSelector = function(region, dir) {
3192-
return $('#' + region.domId + '-section-' + dir);
3212+
return _getDomIdSelector(region, '-section-' + dir);
31933213
};
31943214

31953215
var _getShowFirstSelector = function(region) {
@@ -3204,6 +3224,10 @@ if (!LABKEY.DataRegions) {
32043224
return $('#' + region.showAllID);
32053225
};
32063226

3227+
var _getNavTreeSelectAllSelector = function(region) {
3228+
return _getDomIdSelector(region, '-navtree-select-all');
3229+
}
3230+
32073231
// Formerly, LABKEY.DataRegion.getParamValPairsFromString / LABKEY.DataRegion.getParamValPairs
32083232
var _getParameters = function(region, skipPrefixSet /* optional */) {
32093233

@@ -3327,7 +3351,7 @@ if (!LABKEY.DataRegions) {
33273351
};
33283352

33293353
var _getViewBarSelector = function(region) {
3330-
return $('#' + region.domId + '-viewbar');
3354+
return _getDomIdSelector(region, '-viewbar');
33313355
};
33323356

33333357
var _buttonSelectionBind = function(region, cls, fn) {
@@ -3548,14 +3572,22 @@ if (!LABKEY.DataRegions) {
35483572
_setParameter(region, SHOW_ROWS_PREFIX, showRowsEnum, [OFFSET_PREFIX, MAX_ROWS_PREFIX, SHOW_ROWS_PREFIX]);
35493573
};
35503574

3575+
var _getSelectAllText = function(region) {
3576+
let text = 'Select All Rows';
3577+
if (region.totalRows > MAX_SELECTION_SIZE) {
3578+
text = `Select First ${MAX_SELECTION_SIZE.toLocaleString()} Rows`;
3579+
}
3580+
return text;
3581+
};
3582+
3583+
var _isShowSelectAll = function(region) {
3584+
return region.totalRows && region.totalRows !== region.selectedCount && region.selectedCount < MAX_SELECTION_SIZE;
3585+
};
3586+
35513587
var _showSelectMessage = function(region, msg) {
35523588
if (region.showRecordSelectors) {
3553-
if (region.totalRows && region.totalRows !== region.selectedCount && region.selectedCount < MAX_SELECTION_SIZE) {
3554-
let text = 'Select All Rows';
3555-
if (region.totalRows > MAX_SELECTION_SIZE) {
3556-
text = `Select First ${MAX_SELECTION_SIZE.toLocaleString()} Rows`;
3557-
}
3558-
msg += "&nbsp;<span class='labkey-button select-all'>" + text + "</span>";
3589+
if (_isShowSelectAll(region)) {
3590+
msg += "&nbsp;<span class='labkey-button select-all'>" + _getSelectAllText(region) + "</span>";
35593591
}
35603592

35613593
msg += "&nbsp;" + "<span class='labkey-button select-none'>Select None</span>";
@@ -3583,10 +3615,27 @@ if (!LABKEY.DataRegions) {
35833615
}
35843616
});
35853617

3586-
_getAllRowSelectors(region).each(function() { this.checked = checked === true; });
3618+
_getAllRowSelectors(region).each(function() {
3619+
this.checked = checked === true;
3620+
});
35873621
return ids;
35883622
};
35893623

3624+
var _checkRows = function(region, numRows) {
3625+
const rowSelectors = _getRowSelectors(region);
3626+
3627+
for (let i = 0; i < rowSelectors.length; i++) {
3628+
const el = rowSelectors[i];
3629+
if (!el.disabled) {
3630+
el.checked = i < numRows;
3631+
}
3632+
}
3633+
3634+
_getAllRowSelectors(region).each(function() {
3635+
this.checked = true;
3636+
});
3637+
}
3638+
35903639
/**
35913640
* Asynchronous loader for a DataRegion
35923641
* @param region {DataRegion}

0 commit comments

Comments
 (0)