From 8ba61180f032bdd73d71e6b215706925018abd64 Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Fri, 15 May 2026 23:52:33 -0700 Subject: [PATCH 1/2] More direct Panorama links --- .../api/data/AJAXDetailsDisplayColumn.java | 317 +++++++++--------- 1 file changed, 160 insertions(+), 157 deletions(-) diff --git a/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java b/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java index c750658316f..eef37aed66f 100644 --- a/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java +++ b/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java @@ -1,157 +1,160 @@ -/* - * Copyright (c) 2012-2016 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.labkey.api.data; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.json.JSONObject; -import org.labkey.api.query.DetailsURL; -import org.labkey.api.query.FieldKey; -import org.labkey.api.util.ContainerContext; -import org.labkey.api.util.DOM; -import org.labkey.api.util.GUID; -import org.labkey.api.util.JavaScriptFragment; -import org.labkey.api.util.StringExpression; -import org.labkey.api.view.ActionURL; -import org.labkey.api.view.HttpView; -import org.labkey.api.view.template.ClientDependency; -import org.labkey.api.writer.HtmlWriter; - -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -import static org.labkey.api.util.DOM.SPAN; -import static org.labkey.api.util.DOM.id; - -/** - * Uses LABKEY.Ext.CalloutTip to provide additional details, summoned via AJAX - */ -public class AJAXDetailsDisplayColumn extends DataColumn -{ - @NotNull private final Map _urlParams; - private final JSONObject _properties; - @Nullable private final DetailsURL _detailsURL; - - private final Set _requiredValues = new HashSet<>(); - - public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL detailsURL, @NotNull JSONObject properties) - { - this(col, detailsURL, Collections.emptyMap(), properties); - } - - public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL url, @NotNull Map urlParams, @NotNull JSONObject properties, @NotNull FieldKey containerFieldKey) - { - this(col, url, urlParams, properties); - - if (_detailsURL != null) - _detailsURL.setContainerContext(new ContainerContext.FieldKeyContext(containerFieldKey)); - } - - /** - * @param col base ColumnInfo - * @param url URL with any required static parameters - * @param urlParams parameters that will be swapped in based on the row of data being rendered - * @param properties config passed to LABKEY.Ext.CalloutTip, a subclass of Ext.Tooltip - */ - public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL url, @NotNull Map urlParams, @NotNull JSONObject properties) - { - super(col); - _urlParams = urlParams; - _properties = properties; - _detailsURL = url == null ? null : new DetailsURL(url, urlParams); - } - - @Override - public void renderGridCellContents(RenderContext ctx, HtmlWriter out) - { - String evaluatedURL = null; - if (_detailsURL != null) - { - evaluatedURL = _detailsURL.eval(ctx); - } - - boolean hasAllRequiredValues = true; - for (FieldKey requiredValue : _requiredValues) - { - if (ctx.get(requiredValue) == null) - { - hasAllRequiredValues = false; - break; - } - } - - if (evaluatedURL != null && getValue(ctx) != null && hasAllRequiredValues) - { - String divId = GUID.makeGUID(); - JSONObject props = new JSONObject(_properties.toMap()); - JSONObject autoLoadProp = new JSONObject(); - autoLoadProp.put("url", evaluatedURL); - props.put("autoLoad", autoLoadProp); - props.put("target", divId); - - SPAN( - id(divId), - (DOM.Renderable) ret -> { - super.renderGridCellContents(ctx, out); - return ret; - } - ).appendTo(out); - HttpView.currentPageConfig().addDocumentLoadHandler(JavaScriptFragment.unsafe( - " Ext.onReady(function () { \n" + - " var config = " + props.toString(0) + ";\n" + - " config.autoLoad.callback = function(el, success, response) { if (!success) el.update('Failed to load'); }; \n" + - " var tip = new LABKEY.ext.CalloutTip(config); \n" + - " });" - )); - } - else if (!hasAllRequiredValues) - { - StringExpression url = getURLExpression(); - setURLExpression(null); - super.renderGridCellContents(ctx, out); - setURLExpression(url); - } - else - { - super.renderGridCellContents(ctx, out); - } - } - - /** Require that a column have a non-null value in order to render the link and AJAX behavior for a given row */ - protected void addRequiredValue(FieldKey fieldKey) - { - _requiredValues.add(fieldKey); - } - - @Override - public void addQueryFieldKeys(Set keys) - { - super.addQueryFieldKeys(keys); - keys.addAll(_urlParams.values()); - } - - @NotNull - @Override - public Set getClientDependencies() - { - LinkedHashSet resources = new LinkedHashSet<>(); - resources.add(ClientDependency.fromPath("clientapi/ext3")); - return resources; - } -} +/* + * Copyright (c) 2012-2016 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.labkey.api.data; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.json.JSONObject; +import org.labkey.api.query.DetailsURL; +import org.labkey.api.query.FieldKey; +import org.labkey.api.util.ContainerContext; +import org.labkey.api.util.DOM; +import org.labkey.api.util.GUID; +import org.labkey.api.util.HtmlString; +import org.labkey.api.util.JavaScriptFragment; +import org.labkey.api.util.StringExpression; +import org.labkey.api.view.ActionURL; +import org.labkey.api.view.HttpView; +import org.labkey.api.view.template.ClientDependency; +import org.labkey.api.writer.HtmlWriter; + +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import static org.labkey.api.util.DOM.SPAN; +import static org.labkey.api.util.DOM.id; + +/** + * Uses LABKEY.Ext.CalloutTip to provide additional details, summoned via AJAX + */ +public class AJAXDetailsDisplayColumn extends DataColumn +{ + @NotNull private final Map _urlParams; + private final JSONObject _properties; + @Nullable private final DetailsURL _detailsURL; + + private final Set _requiredValues = new HashSet<>(); + + public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL detailsURL, @NotNull JSONObject properties) + { + this(col, detailsURL, Collections.emptyMap(), properties); + } + + public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL url, @NotNull Map urlParams, @NotNull JSONObject properties, @NotNull FieldKey containerFieldKey) + { + this(col, url, urlParams, properties); + + if (_detailsURL != null) + _detailsURL.setContainerContext(new ContainerContext.FieldKeyContext(containerFieldKey)); + } + + /** + * @param col base ColumnInfo + * @param url URL with any required static parameters + * @param urlParams parameters that will be swapped in based on the row of data being rendered + * @param properties config passed to LABKEY.Ext.CalloutTip, a subclass of Ext.Tooltip + */ + public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL url, @NotNull Map urlParams, @NotNull JSONObject properties) + { + super(col); + _urlParams = urlParams; + _properties = properties; + _detailsURL = url == null ? null : new DetailsURL(url, urlParams); + } + + @Override + public void renderGridCellContents(RenderContext ctx, HtmlWriter out) + { + String evaluatedURL = null; + if (_detailsURL != null) + { + evaluatedURL = _detailsURL.eval(ctx); + } + + boolean hasAllRequiredValues = true; + for (FieldKey requiredValue : _requiredValues) + { + if (ctx.get(requiredValue) == null) + { + hasAllRequiredValues = false; + break; + } + } + + if (evaluatedURL != null && getValue(ctx) != null && hasAllRequiredValues) + { + String divId = GUID.makeGUID(); + JSONObject props = new JSONObject(_properties.toMap()); + JSONObject autoLoadProp = new JSONObject(); + autoLoadProp.put("url", evaluatedURL); + props.put("autoLoad", autoLoadProp); + props.put("target", divId); + + SPAN( + id(divId), + (DOM.Renderable) ret -> { + super.renderGridCellContents(ctx, out); + // U+2060 WORD JOINER: prevents a line break between the name and the popup icon + out.write(HtmlString.unsafe("\u2060")); + return ret; + } + ).appendTo(out); + HttpView.currentPageConfig().addDocumentLoadHandler(JavaScriptFragment.unsafe( + " Ext.onReady(function () { \n" + + " var config = " + props.toString(0) + ";\n" + + " config.autoLoad.callback = function(el, success, response) { if (!success) el.update('Failed to load'); }; \n" + + " var tip = new LABKEY.ext.CalloutTip(config); \n" + + " });" + )); + } + else if (!hasAllRequiredValues) + { + StringExpression url = getURLExpression(); + setURLExpression(null); + super.renderGridCellContents(ctx, out); + setURLExpression(url); + } + else + { + super.renderGridCellContents(ctx, out); + } + } + + /** Require that a column have a non-null value in order to render the link and AJAX behavior for a given row */ + protected void addRequiredValue(FieldKey fieldKey) + { + _requiredValues.add(fieldKey); + } + + @Override + public void addQueryFieldKeys(Set keys) + { + super.addQueryFieldKeys(keys); + keys.addAll(_urlParams.values()); + } + + @NotNull + @Override + public Set getClientDependencies() + { + LinkedHashSet resources = new LinkedHashSet<>(); + resources.add(ClientDependency.fromPath("clientapi/ext3")); + return resources; + } +} From 85a5a73e9cc585fdebbcd63d93bb4aaf016b9d1e Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Sat, 16 May 2026 10:26:27 -0700 Subject: [PATCH 2/2] Line endings? --- .../api/data/AJAXDetailsDisplayColumn.java | 320 +++++++++--------- 1 file changed, 160 insertions(+), 160 deletions(-) diff --git a/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java b/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java index eef37aed66f..6978db798ce 100644 --- a/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java +++ b/api/src/org/labkey/api/data/AJAXDetailsDisplayColumn.java @@ -1,160 +1,160 @@ -/* - * Copyright (c) 2012-2016 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.labkey.api.data; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.json.JSONObject; -import org.labkey.api.query.DetailsURL; -import org.labkey.api.query.FieldKey; -import org.labkey.api.util.ContainerContext; -import org.labkey.api.util.DOM; -import org.labkey.api.util.GUID; -import org.labkey.api.util.HtmlString; -import org.labkey.api.util.JavaScriptFragment; -import org.labkey.api.util.StringExpression; -import org.labkey.api.view.ActionURL; -import org.labkey.api.view.HttpView; -import org.labkey.api.view.template.ClientDependency; -import org.labkey.api.writer.HtmlWriter; - -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -import static org.labkey.api.util.DOM.SPAN; -import static org.labkey.api.util.DOM.id; - -/** - * Uses LABKEY.Ext.CalloutTip to provide additional details, summoned via AJAX - */ -public class AJAXDetailsDisplayColumn extends DataColumn -{ - @NotNull private final Map _urlParams; - private final JSONObject _properties; - @Nullable private final DetailsURL _detailsURL; - - private final Set _requiredValues = new HashSet<>(); - - public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL detailsURL, @NotNull JSONObject properties) - { - this(col, detailsURL, Collections.emptyMap(), properties); - } - - public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL url, @NotNull Map urlParams, @NotNull JSONObject properties, @NotNull FieldKey containerFieldKey) - { - this(col, url, urlParams, properties); - - if (_detailsURL != null) - _detailsURL.setContainerContext(new ContainerContext.FieldKeyContext(containerFieldKey)); - } - - /** - * @param col base ColumnInfo - * @param url URL with any required static parameters - * @param urlParams parameters that will be swapped in based on the row of data being rendered - * @param properties config passed to LABKEY.Ext.CalloutTip, a subclass of Ext.Tooltip - */ - public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL url, @NotNull Map urlParams, @NotNull JSONObject properties) - { - super(col); - _urlParams = urlParams; - _properties = properties; - _detailsURL = url == null ? null : new DetailsURL(url, urlParams); - } - - @Override - public void renderGridCellContents(RenderContext ctx, HtmlWriter out) - { - String evaluatedURL = null; - if (_detailsURL != null) - { - evaluatedURL = _detailsURL.eval(ctx); - } - - boolean hasAllRequiredValues = true; - for (FieldKey requiredValue : _requiredValues) - { - if (ctx.get(requiredValue) == null) - { - hasAllRequiredValues = false; - break; - } - } - - if (evaluatedURL != null && getValue(ctx) != null && hasAllRequiredValues) - { - String divId = GUID.makeGUID(); - JSONObject props = new JSONObject(_properties.toMap()); - JSONObject autoLoadProp = new JSONObject(); - autoLoadProp.put("url", evaluatedURL); - props.put("autoLoad", autoLoadProp); - props.put("target", divId); - - SPAN( - id(divId), - (DOM.Renderable) ret -> { - super.renderGridCellContents(ctx, out); - // U+2060 WORD JOINER: prevents a line break between the name and the popup icon - out.write(HtmlString.unsafe("\u2060")); - return ret; - } - ).appendTo(out); - HttpView.currentPageConfig().addDocumentLoadHandler(JavaScriptFragment.unsafe( - " Ext.onReady(function () { \n" + - " var config = " + props.toString(0) + ";\n" + - " config.autoLoad.callback = function(el, success, response) { if (!success) el.update('Failed to load'); }; \n" + - " var tip = new LABKEY.ext.CalloutTip(config); \n" + - " });" - )); - } - else if (!hasAllRequiredValues) - { - StringExpression url = getURLExpression(); - setURLExpression(null); - super.renderGridCellContents(ctx, out); - setURLExpression(url); - } - else - { - super.renderGridCellContents(ctx, out); - } - } - - /** Require that a column have a non-null value in order to render the link and AJAX behavior for a given row */ - protected void addRequiredValue(FieldKey fieldKey) - { - _requiredValues.add(fieldKey); - } - - @Override - public void addQueryFieldKeys(Set keys) - { - super.addQueryFieldKeys(keys); - keys.addAll(_urlParams.values()); - } - - @NotNull - @Override - public Set getClientDependencies() - { - LinkedHashSet resources = new LinkedHashSet<>(); - resources.add(ClientDependency.fromPath("clientapi/ext3")); - return resources; - } -} +/* + * Copyright (c) 2012-2016 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.labkey.api.data; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.json.JSONObject; +import org.labkey.api.query.DetailsURL; +import org.labkey.api.query.FieldKey; +import org.labkey.api.util.ContainerContext; +import org.labkey.api.util.DOM; +import org.labkey.api.util.GUID; +import org.labkey.api.util.HtmlString; +import org.labkey.api.util.JavaScriptFragment; +import org.labkey.api.util.StringExpression; +import org.labkey.api.view.ActionURL; +import org.labkey.api.view.HttpView; +import org.labkey.api.view.template.ClientDependency; +import org.labkey.api.writer.HtmlWriter; + +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import static org.labkey.api.util.DOM.SPAN; +import static org.labkey.api.util.DOM.id; + +/** + * Uses LABKEY.Ext.CalloutTip to provide additional details, summoned via AJAX + */ +public class AJAXDetailsDisplayColumn extends DataColumn +{ + @NotNull private final Map _urlParams; + private final JSONObject _properties; + @Nullable private final DetailsURL _detailsURL; + + private final Set _requiredValues = new HashSet<>(); + + public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL detailsURL, @NotNull JSONObject properties) + { + this(col, detailsURL, Collections.emptyMap(), properties); + } + + public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL url, @NotNull Map urlParams, @NotNull JSONObject properties, @NotNull FieldKey containerFieldKey) + { + this(col, url, urlParams, properties); + + if (_detailsURL != null) + _detailsURL.setContainerContext(new ContainerContext.FieldKeyContext(containerFieldKey)); + } + + /** + * @param col base ColumnInfo + * @param url URL with any required static parameters + * @param urlParams parameters that will be swapped in based on the row of data being rendered + * @param properties config passed to LABKEY.Ext.CalloutTip, a subclass of Ext.Tooltip + */ + public AJAXDetailsDisplayColumn(@NotNull ColumnInfo col, @Nullable ActionURL url, @NotNull Map urlParams, @NotNull JSONObject properties) + { + super(col); + _urlParams = urlParams; + _properties = properties; + _detailsURL = url == null ? null : new DetailsURL(url, urlParams); + } + + @Override + public void renderGridCellContents(RenderContext ctx, HtmlWriter out) + { + String evaluatedURL = null; + if (_detailsURL != null) + { + evaluatedURL = _detailsURL.eval(ctx); + } + + boolean hasAllRequiredValues = true; + for (FieldKey requiredValue : _requiredValues) + { + if (ctx.get(requiredValue) == null) + { + hasAllRequiredValues = false; + break; + } + } + + if (evaluatedURL != null && getValue(ctx) != null && hasAllRequiredValues) + { + String divId = GUID.makeGUID(); + JSONObject props = new JSONObject(_properties.toMap()); + JSONObject autoLoadProp = new JSONObject(); + autoLoadProp.put("url", evaluatedURL); + props.put("autoLoad", autoLoadProp); + props.put("target", divId); + + SPAN( + id(divId), + (DOM.Renderable) ret -> { + super.renderGridCellContents(ctx, out); + // U+2060 WORD JOINER: prevents a line break between the name and the popup icon + out.write(HtmlString.unsafe("\u2060")); + return ret; + } + ).appendTo(out); + HttpView.currentPageConfig().addDocumentLoadHandler(JavaScriptFragment.unsafe( + " Ext.onReady(function () { \n" + + " var config = " + props.toString(0) + ";\n" + + " config.autoLoad.callback = function(el, success, response) { if (!success) el.update('Failed to load'); }; \n" + + " var tip = new LABKEY.ext.CalloutTip(config); \n" + + " });" + )); + } + else if (!hasAllRequiredValues) + { + StringExpression url = getURLExpression(); + setURLExpression(null); + super.renderGridCellContents(ctx, out); + setURLExpression(url); + } + else + { + super.renderGridCellContents(ctx, out); + } + } + + /** Require that a column have a non-null value in order to render the link and AJAX behavior for a given row */ + protected void addRequiredValue(FieldKey fieldKey) + { + _requiredValues.add(fieldKey); + } + + @Override + public void addQueryFieldKeys(Set keys) + { + super.addQueryFieldKeys(keys); + keys.addAll(_urlParams.values()); + } + + @NotNull + @Override + public Set getClientDependencies() + { + LinkedHashSet resources = new LinkedHashSet<>(); + resources.add(ClientDependency.fromPath("clientapi/ext3")); + return resources; + } +}