diff --git a/api/src/org/labkey/api/data/AbstractExcelDisplayColumn.java b/api/src/org/labkey/api/data/AbstractExcelDisplayColumn.java index e28d35d3e59..94fa421e31f 100644 --- a/api/src/org/labkey/api/data/AbstractExcelDisplayColumn.java +++ b/api/src/org/labkey/api/data/AbstractExcelDisplayColumn.java @@ -4,7 +4,6 @@ import org.labkey.api.view.ActionURL; import org.labkey.api.writer.HtmlWriter; -import java.io.IOException; import java.io.Writer; public abstract class AbstractExcelDisplayColumn extends DisplayColumn @@ -44,24 +43,12 @@ public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) throw new UnsupportedOperationException("This is for excel only."); } - @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) - { - throw new UnsupportedOperationException("This is for excel only."); - } - @Override public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) { throw new UnsupportedOperationException("This is for excel only."); } - @Override - protected void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object value) throws IOException - { - throw new UnsupportedOperationException("This is for excel only."); - } - @Override public HtmlString getTitle(RenderContext ctx) { diff --git a/api/src/org/labkey/api/data/DataColumn.java b/api/src/org/labkey/api/data/DataColumn.java index 1c4cf1d1ca9..4adbefe90dc 100644 --- a/api/src/org/labkey/api/data/DataColumn.java +++ b/api/src/org/labkey/api/data/DataColumn.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.labkey.api.action.SpringActionController; +import org.labkey.api.collections.LabKeyCollectors; import org.labkey.api.collections.NamedObject; import org.labkey.api.collections.NamedObjectList; import org.labkey.api.exp.property.IPropertyValidator; @@ -33,6 +34,7 @@ import org.labkey.api.settings.OptionalFeatureService; import org.labkey.api.stats.AnalyticsProviderRegistry; import org.labkey.api.stats.ColumnAnalyticsProvider; +import org.labkey.api.util.DOM.Renderable; import org.labkey.api.util.HtmlString; import org.labkey.api.util.HtmlStringBuilder; import org.labkey.api.util.JavaScriptFragment; @@ -65,6 +67,12 @@ import java.util.Objects; import java.util.Set; +import static org.labkey.api.util.DOM.DIV; +import static org.labkey.api.util.DOM.SPAN; +import static org.labkey.api.util.DOM.TD; +import static org.labkey.api.util.DOM.cl; +import static org.labkey.api.util.DOM.id; + /** Subclass that wraps a ColumnInfo to pull values from the database */ public class DataColumn extends DisplayColumn { @@ -313,19 +321,19 @@ public Object getJsonValue(RenderContext ctx) } @Override - public Class getValueClass() + public Class getValueClass() { return _boundColumn.getJavaClass(); } @Override - public Class getDisplayValueClass() + public Class getDisplayValueClass() { return _displayColumn.getJavaClass(); } @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException + public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) { // By default, use the same rendering for both the details and grid views renderGridCellContents(ctx, out); @@ -633,7 +641,7 @@ protected String getStringValue(Object value, boolean disabledInput) } @Override - public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object value) throws IOException + public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) { if (_boundColumn.isVersionColumn() || _inputType.equalsIgnoreCase("none")) return; @@ -647,12 +655,12 @@ public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, renderHiddenFormInput(out, formFieldName, value); if (null != value) { - oldWriter.write(PageFlowUtil.filter(strVal)); + out.write(strVal); } } else if (_inputType.toLowerCase().startsWith("disabled")) { - renderTextFormInput(oldWriter, formFieldName, value, strVal, true); + renderTextFormInput(out, formFieldName, value, strVal, true); } else if (_inputType.toLowerCase().startsWith("select")) { @@ -662,42 +670,43 @@ else if (_inputType.toLowerCase().startsWith("select")) displayColumn.renderInputHtml(ctx, out, value); } else - renderSelectFormInputFromFk(ctx, oldWriter, formFieldName, value, strVal, disabledInput); + renderSelectFormInputFromFk(ctx, out, formFieldName, value, strVal, disabledInput); } else if (_inputType.equalsIgnoreCase("textarea")) { - renderTextAreaFormInput(oldWriter, formFieldName, value, strVal, disabledInput); + renderTextAreaFormInput(out, formFieldName, value, strVal, disabledInput); } else if (_inputType.equalsIgnoreCase("file")) { - renderFileFormInput(oldWriter, formFieldName, value, strVal, disabledInput); + renderFileFormInput(out, formFieldName, value, strVal, disabledInput); } else if (_inputType.equalsIgnoreCase("checkbox")) { - renderCheckboxFormInput(oldWriter, formFieldName, value, strVal, disabledInput); + renderCheckboxFormInput(out, formFieldName, value, strVal, disabledInput); } else { if (getAutoCompleteURLPrefix() != null) { - renderAutoCompleteFormInput(ctx, oldWriter, formFieldName, value, strVal, disabledInput, getAutoCompleteURLPrefix()); + renderAutoCompleteFormInput(ctx, out, formFieldName, value, strVal, disabledInput, getAutoCompleteURLPrefix()); } else { IPropertyValidator textChoiceValidator = PropertyService.get().getValidatorForColumn(_boundColumn, PropertyValidatorType.TextChoice); if (textChoiceValidator != null) - renderTextChoiceFormInput(oldWriter, formFieldName, value, strVal, disabledInput, textChoiceValidator); + renderTextChoiceFormInput(out, formFieldName, value, strVal, disabledInput, textChoiceValidator); else - renderTextFormInput(oldWriter, formFieldName, value, strVal, disabledInput); + renderTextFormInput(out, formFieldName, value, strVal, disabledInput); } } HtmlString errors = getErrors(ctx); - if (!StringUtils.isEmpty(errors.toString())) + if (!errors.isEmpty()) { - oldWriter.write(""); - oldWriter.write(errors.toString()); - oldWriter.write(""); + SPAN( + cl("help-block form-text"), + errors + ).appendTo(out); } } @@ -710,10 +719,7 @@ else if (_inputType.equalsIgnoreCase("checkbox")) return ctx.getForm() == null || col == null ? HtmlString.EMPTY_STRING : ctx.getErrors(col); } - private void renderSelectFormInput( - Writer out, String formFieldName, Object value, String strVal, - boolean disabledInput, NamedObjectList entryList - ) throws IOException + private void renderSelectFormInput(HtmlWriter out, String formFieldName, Object value, String strVal, boolean disabledInput, NamedObjectList entryList) { Select.SelectBuilder select = new Select.SelectBuilder() .disabled(disabledInput) @@ -738,15 +744,14 @@ private void renderSelectFormInput( options.add(option.build()); } - out.write(select.addOptions(options).toString()); + out.write(select.addOptions(options)); // disabled inputs are not posted with the form, so we output a hidden form element: if (disabledInput) - renderHiddenFormInput(HtmlWriter.of(out), formFieldName, value); + renderHiddenFormInput(out, formFieldName, value); } - private void renderTextChoiceFormInput(Writer out, String formFieldName, Object value, String strVal, boolean disabledInput, IPropertyValidator textChoiceValidator) - throws IOException + private void renderTextChoiceFormInput(HtmlWriter out, String formFieldName, Object value, String strVal, boolean disabledInput, IPropertyValidator textChoiceValidator) { NamedObjectList options = new NamedObjectList(); List choices = PropertyService.get().getTextChoiceValidatorOptions(textChoiceValidator); @@ -764,8 +769,7 @@ private void renderTextChoiceFormInput(Writer out, String formFieldName, Object renderSelectFormInput(out, formFieldName, value, strVal, disabledInput, options); } - protected void renderSelectFormInputFromFk(RenderContext ctx, Writer out, String formFieldName, Object value, String strVal, boolean disabledInput) - throws IOException + protected void renderSelectFormInputFromFk(RenderContext ctx, HtmlWriter out, String formFieldName, Object value, String strVal, boolean disabledInput) { ForeignKey boundColumnFK = _boundColumn.getFk(); NamedObjectList entryList = boundColumnFK.getSelectList(ctx); @@ -791,8 +795,7 @@ protected void renderSelectFormInputFromFk(RenderContext ctx, Writer out, String } } - protected void renderFileFormInput(Writer out, String formFieldName, Object value, String strVal, boolean disabledInput) - throws IOException + protected void renderFileFormInput(HtmlWriter out, String formFieldName, Object value, String strVal, boolean disabledInput) { var input = new Input.InputBuilder<>() .type("file") @@ -800,11 +803,10 @@ protected void renderFileFormInput(Writer out, String formFieldName, Object valu .disabled(disabledInput) .needsWrapping(false); - out.write(input.build().toString()); + out.write(input); } - protected void renderCheckboxFormInput(Writer out, String formFieldName, Object value, String strVal, boolean disabledInput) - throws IOException + protected void renderCheckboxFormInput(HtmlWriter out, String formFieldName, Object value, String strVal, boolean disabledInput) { boolean checked = ColumnInfo.booleanFromObj(ConvertUtils.convert(value)); @@ -816,7 +818,7 @@ protected void renderCheckboxFormInput(Writer out, String formFieldName, Object .checked(checked) .needsWrapping(false); - out.write(input.build().toString()); + out.write(input); /* * Checkboxes are weird. If set to FALSE they don't post at all, so it's impossible to tell @@ -826,17 +828,17 @@ protected void renderCheckboxFormInput(Writer out, String formFieldName, Object * To fix this, each checkbox posts a hidden field named @columnName. Spring parameter * binding uses these special fields to set all unposted checkbox values to false. */ - out.write(""); + out.write(new Input.InputBuilder<>() + .type("hidden") + .name(SpringActionController.FIELD_MARKER + formFieldName) + .value(1)); + // disabled inputs are not posted with the form, so we output a hidden form element: if (disabledInput) - renderHiddenFormInput(HtmlWriter.of(out), formFieldName, checked ? "1" : ""); + renderHiddenFormInput(out, formFieldName, checked ? "1" : ""); } - protected void renderTextAreaFormInput(Writer out, String formFieldName, Object value, String strVal, boolean disabledInput) - throws IOException + protected void renderTextAreaFormInput(HtmlWriter out, String formFieldName, Object value, String strVal, boolean disabledInput) { TextArea.TextAreaBuilder input = new TextArea.TextAreaBuilder() .columns(_inputLength) @@ -845,15 +847,14 @@ protected void renderTextAreaFormInput(Writer out, String formFieldName, Object .disabled(disabledInput) .value(strVal); - out.write(input.build().toString()); + out.write(input); // disabled inputs are not posted with the form, so we output a hidden form element: if (disabledInput) - renderHiddenFormInput(HtmlWriter.of(out), formFieldName, value); + renderHiddenFormInput(out, formFieldName, value); } - protected void renderTextFormInput(Writer out, String formFieldName, Object value, String strVal, boolean disabledInput) - throws IOException + protected void renderTextFormInput(HtmlWriter out, String formFieldName, Object value, String strVal, boolean disabledInput) { var input = new Input.InputBuilder<>() .name(formFieldName) @@ -862,18 +863,20 @@ protected void renderTextFormInput(Writer out, String formFieldName, Object valu .value(strVal) .needsWrapping(false); - out.write(input.build().toString()); + out.write(input); // disabled inputs are not posted with the form, so we output a hidden form element: if (disabledInput) - renderHiddenFormInput(HtmlWriter.of(out), formFieldName, value); + renderHiddenFormInput(out, formFieldName, value); } - protected void renderAutoCompleteFormInput(RenderContext ctx, Writer out, String formFieldName, Object value, String strVal, boolean disabledInput, @NotNull ActionURL autoCompleteURLPrefix) - throws IOException + protected void renderAutoCompleteFormInput(RenderContext ctx, HtmlWriter out, String formFieldName, Object value, String strVal, boolean disabledInput, @NotNull ActionURL autoCompleteURLPrefix) { String renderId = "auto-complete-div-" + UniqueID.getRequestScopedUID(ctx.getRequest()); - out.write("
"); + DIV( + id(renderId) + ).appendTo(out); + String initScript = "Ext4.onReady(function(){\n" + " Ext4.create('LABKEY.element.AutoCompletionField', {\n" + @@ -941,57 +944,44 @@ public void renderDetailsCaptionCell(RenderContext ctx, HtmlWriter out, @Nullabl if (null == _caption) return; - Writer oldWriter = out.unwrap(); - try - { - oldWriter.write(""); - - HtmlString title = getTitle(ctx); - if (title != null) - oldWriter.write(title.toString()); - if (ctx.getMode() == DataRegion.MODE_DETAILS) - oldWriter.write(":"); - int mode = ctx.getMode(); - if ((mode == DataRegion.MODE_INSERT || mode == DataRegion.MODE_UPDATE) && isEditable()) - { - if (_boundColumn != null) + TD( + cl(cls != null, cls, "lk-form-label"), + getTitle(ctx), + ctx.getMode() == DataRegion.MODE_DETAILS ? ":" : null, + (Renderable) ret -> { + + int mode = ctx.getMode(); + if ((mode == DataRegion.MODE_INSERT || mode == DataRegion.MODE_UPDATE) && isEditable()) { - List helpLines = new LinkedList<>() + if (_boundColumn != null) { - @Override - public boolean add(String s) + List helpLines = new LinkedList<>(); + if (_boundColumn.getFriendlyTypeName() != null && !_inputType.toLowerCase().startsWith("select")) { - return super.add(PageFlowUtil.filter(s)); + helpLines.add(HtmlString.of("Type: " + _boundColumn.getFriendlyTypeName())); + } + if (_boundColumn.getDescription() != null) + { + helpLines.add(HtmlString.of("Description: " + _boundColumn.getDescription())); + } + for (IPropertyValidator validator : _boundColumn.getValidators()) + helpLines.add(HtmlString.of("Validator: " + validator)); + if (renderRequiredIndicators() && _boundColumn.isRequired() && !_boundColumn.isBooleanType()) + { + out.write(" *"); + helpLines.add(HtmlString.of("This field is required.")); + } + if (!helpLines.isEmpty()) + { + HtmlString helpHtml = helpLines.stream().collect(LabKeyCollectors.joining(HtmlString.BR)); + out.write(PageFlowUtil.popupHelp(helpHtml, _boundColumn.getLabel())); } - }; - if (_boundColumn.getFriendlyTypeName() != null && !_inputType.toLowerCase().startsWith("select")) - { - helpLines.add("Type: " + _boundColumn.getFriendlyTypeName()); - } - if (_boundColumn.getDescription() != null) - { - helpLines.add("Description: " + _boundColumn.getDescription()); - } - for (IPropertyValidator validator : _boundColumn.getValidators()) - helpLines.add("Validator: " + validator); - if (renderRequiredIndicators() && _boundColumn.isRequired() && !_boundColumn.isBooleanType()) - { - oldWriter.write(" *"); - helpLines.add("This field is required."); - } - if (!helpLines.isEmpty()) - { - HtmlString helpHtml = HtmlString.unsafe(StringUtils.join(helpLines, "
")); - PageFlowUtil.popupHelp(helpHtml, _boundColumn.getLabel()).appendTo(oldWriter); } } + + return ret; } - oldWriter.write("\n"); - } - catch (IOException e) - { - throw new RuntimeException(e); - } + ).appendTo(out); } protected boolean renderRequiredIndicators() diff --git a/api/src/org/labkey/api/data/DisplayColumn.java b/api/src/org/labkey/api/data/DisplayColumn.java index af574b493bb..ac64180b7b5 100644 --- a/api/src/org/labkey/api/data/DisplayColumn.java +++ b/api/src/org/labkey/api/data/DisplayColumn.java @@ -144,10 +144,10 @@ public boolean shouldRenderInCurrentRow(RenderContext ctx) /* Note: DataRegion plus its subclasses and the vast majority of DisplayColumn (and subclasses) have been rewritten to use HtmlWriter, DOM, and builders instead of String-based HTML generation. They also no longer throw - IOException. The three deprecated methods below that take both Writer and HtmlWriter are temporary, present only - until their overrides are migrated to use HtmlWriter, DOM, and builders, and adjusted to override the - corresponding non-Writer variant. Once migrated, the deprecated methods will be removed and the non-deprecated - variants will be made abstract. + IOException. The deprecated renderGridCellContents() variant below that take both Writer and HtmlWriter is + temporary, present only until its overrides are migrated to use HtmlWriter, DOM, and builders, and adjusted to + override the corresponding non-Writer variant. Once migrated, the deprecated method will be removed and the + non-deprecated variant will be made abstract. */ public void renderGridCellContents(RenderContext ctx, HtmlWriter out) @@ -169,43 +169,9 @@ protected void renderGridCellContents(RenderContext ctx, Writer oldWriter, HtmlW throw new IllegalStateException("Must override renderGridCellContents()"); } - public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) - { - try - { - renderDetailsCellContents(ctx, out.unwrap(), out); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - - // No callers (other than just above) - @Deprecated - protected void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException - { - throw new IllegalStateException("Must override renderDetailsCellContents()"); - } + public abstract void renderDetailsCellContents(RenderContext ctx, HtmlWriter out); - public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) - { - try - { - renderInputHtml(ctx, out.unwrap(), out, value); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - - // No callers (other than just above) - @Deprecated - protected void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object value) throws IOException - { - throw new IllegalStateException("Must override renderInputHtml()"); - } + public abstract void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value); public @Nullable HtmlString getTitle(RenderContext ctx) { diff --git a/api/src/org/labkey/api/data/MVDisplayColumn.java b/api/src/org/labkey/api/data/MVDisplayColumn.java index 19d0aa512bc..d3fa3aef0aa 100644 --- a/api/src/org/labkey/api/data/MVDisplayColumn.java +++ b/api/src/org/labkey/api/data/MVDisplayColumn.java @@ -20,10 +20,9 @@ import org.labkey.api.util.HtmlString; import org.labkey.api.util.HtmlStringBuilder; import org.labkey.api.util.PageFlowUtil; +import org.labkey.api.util.element.Select.SelectBuilder; import org.labkey.api.writer.HtmlWriter; -import java.io.IOException; -import java.io.Writer; import java.util.Set; import static org.labkey.api.util.DOM.Attribute.style; @@ -180,57 +179,37 @@ public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) { DIV(at(style,"margin-top:5px")).appendTo(out); super.renderInputHtml(ctx, out, value); - try - { - renderMVPicker(ctx, out); - } - catch (IOException e) - { - throw new RuntimeException(e); - } + renderMVPicker(ctx, out); } - private void renderMVPicker(RenderContext ctx, HtmlWriter out) throws IOException + private void renderMVPicker(RenderContext ctx, HtmlWriter out) { - Writer oldWriter = out.unwrap(); String formFieldName = ctx.getForm().getFormFieldName(mvIndicatorColumn); String selectedMvIndicator = getMvIndicator(ctx); Set mvIndicators = MvUtil.getMvIndicators(ctx.getContainer()); - oldWriter.write("Missing Value Indicator: "); - oldWriter.write(""); - // disabled inputs are not posted with the form, so we output a hidden form element: - //if (isDisabledInput()) - // renderHiddenFormInput(ctx, out, formFieldName, value); - } - - private void outputName(RenderContext ctx, Writer out, String formFieldName) throws IOException - { - out.write(" name=\""); - out.write(PageFlowUtil.filter(formFieldName)); - out.write("\""); - String setFocusId = (String)ctx.get("setFocusId"); if (null != setFocusId) { - out.write(" id=\"" + PageFlowUtil.filter(setFocusId) + "\""); ctx.remove("setFocusId"); } + + out.write("Missing Value Indicator:"); + out.write(HtmlString.NBSP); + + new SelectBuilder() + .addStyle("margin-bottom:5px") + .addStyle("margin-top:2px") + .className(null) + .name(formFieldName) + .id(setFocusId) + .disabled(isDisabledInput()) + .addOption("") + .addOptions(mvIndicators) + .selected(selectedMvIndicator) + .appendTo(out); + + // disabled inputs are not posted with the form, so we output a hidden form element: + //if (isDisabledInput()) + // renderHiddenFormInput(ctx, out, formFieldName, value); } } diff --git a/api/src/org/labkey/api/data/SimpleDisplayColumn.java b/api/src/org/labkey/api/data/SimpleDisplayColumn.java index d64f56277ba..d9733aca1c2 100644 --- a/api/src/org/labkey/api/data/SimpleDisplayColumn.java +++ b/api/src/org/labkey/api/data/SimpleDisplayColumn.java @@ -110,11 +110,11 @@ public Object getValue(RenderContext ctx) } @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException + public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) { Object value = getValue(ctx); if (value != null) - oldWriter.write(value.toString()); + out.write(value.toString()); } @Override @@ -167,12 +167,6 @@ public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) throw new UnsupportedOperationException("Non Bound columns not editable for " + this); } - @Override - public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object value) throws IOException - { - throw new UnsupportedOperationException("Non Bound columns not editable for " + this); - } - @Override public @NotNull HtmlString getTitle(RenderContext ctx) { diff --git a/api/src/org/labkey/api/query/PropertiesDisplayColumn.java b/api/src/org/labkey/api/query/PropertiesDisplayColumn.java index 76d27bf07ad..a87089063ac 100644 --- a/api/src/org/labkey/api/query/PropertiesDisplayColumn.java +++ b/api/src/org/labkey/api/query/PropertiesDisplayColumn.java @@ -279,7 +279,7 @@ public boolean isEditable() } @Override - public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object value) + public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) { // no-op } diff --git a/api/src/org/labkey/api/study/actions/StudyPickerColumn.java b/api/src/org/labkey/api/study/actions/StudyPickerColumn.java index 67a5b5768db..1cd82aad728 100644 --- a/api/src/org/labkey/api/study/actions/StudyPickerColumn.java +++ b/api/src/org/labkey/api/study/actions/StudyPickerColumn.java @@ -26,6 +26,7 @@ import org.labkey.api.security.permissions.ReadPermission; import org.labkey.api.study.Study; import org.labkey.api.study.publish.StudyPublishService; +import org.labkey.api.util.DOM.Renderable; import org.labkey.api.util.HtmlString; import org.labkey.api.util.PageFlowUtil; import org.labkey.api.util.element.Input; @@ -33,10 +34,11 @@ import org.labkey.api.util.element.Select.SelectBuilder; import org.labkey.api.writer.HtmlWriter; -import java.io.IOException; -import java.io.Writer; import java.util.Set; +import static org.labkey.api.util.DOM.TD; +import static org.labkey.api.util.DOM.cl; + public class StudyPickerColumn extends UploadWizardAction.InputDisplayColumn { ColumnInfo _colInfo; @@ -69,29 +71,25 @@ public void renderDetailsCaptionCell(RenderContext ctx, HtmlWriter out, @Nullabl if (null == _caption) return; - Writer oldWriter = out.unwrap(); - try - { - oldWriter.write(""); - oldWriter.write(getTitle(ctx).toString()); - int mode = ctx.getMode(); - if (mode == DataRegion.MODE_INSERT || mode == DataRegion.MODE_UPDATE) - { - if (_colInfo != null) + TD( + cl(cls != null ? cls : "lk-form-label"), + getTitle(ctx), + (Renderable) ret -> { + int mode = ctx.getMode(); + if (mode == DataRegion.MODE_INSERT || mode == DataRegion.MODE_UPDATE) { - String helpPopupText = ((_colInfo.getFriendlyTypeName() != null) ? "Type: " + _colInfo.getFriendlyTypeName() + "\n" : "") + - ((_colInfo.getDescription() != null) ? "Description: " + _colInfo.getDescription() + "\n" : ""); - PageFlowUtil.popupHelp(HtmlString.of(helpPopupText), _colInfo.getName()); - if (!_colInfo.isNullable()) - oldWriter.write(" *"); + if (_colInfo != null) + { + String helpPopupText = ((_colInfo.getFriendlyTypeName() != null) ? "Type: " + _colInfo.getFriendlyTypeName() + "\n" : "") + + ((_colInfo.getDescription() != null) ? "Description: " + _colInfo.getDescription() + "\n" : ""); + out.write(PageFlowUtil.popupHelp(HtmlString.of(helpPopupText), _colInfo.getName())); + if (!_colInfo.isNullable()) + out.write(" *"); + } } + return ret; } - oldWriter.write(""); - } - catch (IOException e) - { - throw new RuntimeException(e); - } + ).appendTo(out); } protected boolean isDisabledInput() diff --git a/api/src/org/labkey/api/util/element/Input.java b/api/src/org/labkey/api/util/element/Input.java index 1d89218b78d..a5db642b100 100644 --- a/api/src/org/labkey/api/util/element/Input.java +++ b/api/src/org/labkey/api/util/element/Input.java @@ -16,6 +16,7 @@ package org.labkey.api.util.element; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.labkey.api.data.RenderContext; import org.labkey.api.util.HasHtmlString; @@ -122,6 +123,7 @@ public static State get(String stateName) private final @Nullable HtmlString _value; private final Integer _tabIndex; private final List _styles; + private final List _dataAttributes; protected Input(InputBuilder builder) { @@ -169,6 +171,7 @@ protected Input(InputBuilder builder) _needsWrapping = builder._needsWrapping == null || builder._needsWrapping; _tabIndex = builder._tabIndex; _styles = builder._styles; + _dataAttributes = builder._dataAttributes; } public String getAutoComplete() @@ -406,6 +409,11 @@ public List getStyles() return _styles; } + private List getDataAttributes() + { + return _dataAttributes; + } + @Override public void render(RenderContext ctx, Writer out) throws IOException { @@ -566,6 +574,7 @@ protected void doInput(Appendable sb) throws IOException sb.append(" tabIndex=\"").append(h(_tabIndex)).append("\""); doStyles(sb); + doDataAttributes(sb); if (!HtmlString.isBlank(getValue())) sb.append(" value=\"").append(h(getValue())).append("\""); doInputEvents(id); @@ -610,6 +619,20 @@ protected void doStyles(Appendable sb) throws IOException } } + protected void doDataAttributes(Appendable sb) + { + getDataAttributes().forEach(attr -> { + try + { + sb.append(" data-").append(attr.name()).append("=\"").append(h(attr.value())).append("\""); + } + catch (IOException io) + { + UnexpectedException.rethrow(io); + } + }); + } + protected void doInputEvents(String id) { var pageConfig = HttpView.currentPageConfig(); @@ -760,6 +783,9 @@ public static class InputBuilder> implements HasHtmlSt private Integer _tabIndex; private final List _styles = new LinkedList<>(); + private final List _dataAttributes = new LinkedList<>(); + + private record DataAttribute(String name, String value) {} public InputBuilder() { @@ -1061,6 +1087,13 @@ public T addStyles(List styles) return (T)this; } + // Add an arbitrary "data-" attribute. Name should not include "data-"... the builder will add prefix. + public T addDataAttribute(@NotNull String name, @NotNull String value) + { + _dataAttributes.add(new DataAttribute(name, value)); + return (T)this; + } + public Input build() { return new Input(this); diff --git a/api/src/org/labkey/api/util/element/Select.java b/api/src/org/labkey/api/util/element/Select.java index 38d3bb94ba9..e42b8c80b52 100644 --- a/api/src/org/labkey/api/util/element/Select.java +++ b/api/src/org/labkey/api/util/element/Select.java @@ -71,6 +71,8 @@ protected void doInput(Appendable sb) throws IOException doStyles(sb); + doDataAttributes(sb); + doInputEvents(id); if (isDisabled()) diff --git a/api/src/org/labkey/api/view/ColorPickerDisplayColumn.java b/api/src/org/labkey/api/view/ColorPickerDisplayColumn.java index be7cd445224..b6fa6a6c79e 100644 --- a/api/src/org/labkey/api/view/ColorPickerDisplayColumn.java +++ b/api/src/org/labkey/api/view/ColorPickerDisplayColumn.java @@ -18,12 +18,15 @@ import org.labkey.api.data.ColumnInfo; import org.labkey.api.data.DataColumn; import org.labkey.api.data.RenderContext; +import org.labkey.api.util.JavaScriptFragment; import org.labkey.api.util.PageFlowUtil; import org.labkey.api.util.UniqueID; import org.labkey.api.writer.HtmlWriter; -import java.io.IOException; -import java.io.Writer; +import static org.labkey.api.util.DOM.Attribute.style; +import static org.labkey.api.util.DOM.DIV; +import static org.labkey.api.util.DOM.SCRIPT; +import static org.labkey.api.util.DOM.at; /** * {@link org.labkey.api.data.DisplayColumn} that shows an ExtJS-based color picker component for insert/update forms @@ -37,29 +40,31 @@ public ColorPickerDisplayColumn(ColumnInfo col) } @Override - public void renderGridCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException + public void renderGridCellContents(RenderContext ctx, HtmlWriter out) { Object value = getValue(ctx); if (value != null) { - oldWriter.write("
"); + DIV( + at(style, "height: 20px; width: 20px; background: #" + value) + ).appendTo(out); } } @Override - public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object value) throws IOException + public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) { String name = getFormFieldName(ctx); renderHiddenFormInput(out, name, value); String renderId = "color-picker-div-" + UniqueID.getRequestScopedUID(ctx.getRequest()); - oldWriter.write(""); - oldWriter.write("
"); + " });\n") + ).appendTo(out); + + DIV(renderId).appendTo(out); } } diff --git a/api/src/org/labkey/api/view/TypeAheadSelectDisplayColumn.java b/api/src/org/labkey/api/view/TypeAheadSelectDisplayColumn.java index 91398c2f446..9dd53bcbebb 100644 --- a/api/src/org/labkey/api/view/TypeAheadSelectDisplayColumn.java +++ b/api/src/org/labkey/api/view/TypeAheadSelectDisplayColumn.java @@ -22,15 +22,18 @@ import org.labkey.api.data.DisplayColumnFactory; import org.labkey.api.data.ForeignKey; import org.labkey.api.data.RenderContext; +import org.labkey.api.util.JavaScriptFragment; import org.labkey.api.util.PageFlowUtil; import org.labkey.api.util.UniqueID; import org.labkey.api.writer.HtmlWriter; -import java.io.IOException; -import java.io.Writer; import java.util.Collection; import java.util.Collections; +import static org.labkey.api.util.DOM.DIV; +import static org.labkey.api.util.DOM.SCRIPT; +import static org.labkey.api.util.DOM.id; + /** * {@link DisplayColumn} that use a React QuerySelect component input to allow for type-ahead search/filter * for a select input that has too many options for a user to meaningfully scroll through. @@ -47,13 +50,13 @@ public TypeAheadSelectDisplayColumn(ColumnInfo col, Integer maxRows) } @Override - public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object value) throws IOException + public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) { ForeignKey fk = getBoundColumn().getFk(); // currently only supported for lookup columns with a defined schema/query if (fk == null) { - oldWriter.write("TypeAheadSelectDisplayColumn can only be used with a lookup column."); + out.write("TypeAheadSelectDisplayColumn can only be used with a lookup column."); return; } @@ -63,7 +66,6 @@ public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, String renderId = "query-select-div-" + UniqueID.getRequestScopedUID(ctx.getRequest()); StringBuilder sb = new StringBuilder(); - sb.append("\n"); - sb.append("
"); - oldWriter.write(sb.toString()); + + SCRIPT( + JavaScriptFragment.unsafe(sb.toString()) + ).appendTo(out); + + DIV( + id(renderId) + ).appendTo(out); // disabled inputs are not posted with the form, so we output a hidden form element: if (disabledInput) diff --git a/assay/api-src/org/labkey/api/assay/plate/PlateSampleFilePropertyHelper.java b/assay/api-src/org/labkey/api/assay/plate/PlateSampleFilePropertyHelper.java index e795e7b6b50..8fc1b23943d 100644 --- a/assay/api-src/org/labkey/api/assay/plate/PlateSampleFilePropertyHelper.java +++ b/assay/api-src/org/labkey/api/assay/plate/PlateSampleFilePropertyHelper.java @@ -39,7 +39,9 @@ import org.labkey.api.security.User; import org.labkey.api.study.assay.SampleMetadataInputFormat; import org.labkey.api.util.HtmlString; +import org.labkey.api.util.JavaScriptFragment; import org.labkey.api.util.PageFlowUtil; +import org.labkey.api.util.element.Input.InputBuilder; import org.labkey.api.view.HttpView; import org.labkey.api.view.InsertView; import org.labkey.api.view.template.PageConfig; @@ -53,7 +55,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.Writer; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -61,6 +62,15 @@ import java.util.Objects; import java.util.Set; +import static org.labkey.api.util.DOM.Attribute.style; +import static org.labkey.api.util.DOM.DIV; +import static org.labkey.api.util.DOM.SCRIPT; +import static org.labkey.api.util.DOM.TABLE; +import static org.labkey.api.util.DOM.TD; +import static org.labkey.api.util.DOM.TR; +import static org.labkey.api.util.DOM.cl; +import static org.labkey.api.util.DOM.id; + public class PlateSampleFilePropertyHelper extends PlateSamplePropertyHelper { private static final String SAMPLE_FILE_INPUT_NAME = "__sampleMetadataFile__"; @@ -320,7 +330,6 @@ public boolean isEditable() @Override public void renderDetailsCaptionCell(RenderContext ctx, HtmlWriter out, @Nullable String cls) { - if (_metadataInputFormat == SampleMetadataInputFormat.FILE_BASED) { String nounV1 = includesViruses ? "Sample/Virus" : "Sample"; @@ -330,75 +339,88 @@ public void renderDetailsCaptionCell(RenderContext ctx, HtmlWriter out, @Nullabl ". This information is used to determine data processing and to map " + nounV2.toLowerCase() + " values to plate locations."), nounV1 + " Metadata"); - Writer oldWriter = out.unwrap(); - try - { - oldWriter.write(""); - oldWriter.write(nounV1 + " Metadata"); - builder.appendTo(oldWriter); - oldWriter.write(" *"); - } - catch (IOException e) - { - throw new RuntimeException(e); - } + TD( + cl(cls != null ? cls : "lk-form-label"), + nounV1 + " Metadata", + builder, + " *" + ).appendTo(out); } } @Override public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) { - Writer oldWriter = out.unwrap(); - try + if (_metadataInputFormat == SampleMetadataInputFormat.FILE_BASED) { - if (_metadataInputFormat == SampleMetadataInputFormat.FILE_BASED) + String nounV1 = includesViruses ? "Sample/Virus" : "Sample"; + String nounV2 = includesViruses ? "Sample and virus" : "Sample"; + + out.write(nounV2 + " metadata should be uploaded in a TSV, CSV or Excel file with one row per " + nounV1.toLowerCase() + ". "); + out.write(PageFlowUtil.link("Download template", PageFlowUtil.urlProvider(NabUrls.class).getSampleXLSTemplateURL(_container, _protocol))); + out.write(HtmlString.BR); + + if (reshowFile != null) { - String nounV1 = includesViruses ? "Sample/Virus" : "Sample"; - String nounV2 = includesViruses ? "Sample and virus" : "Sample"; - - oldWriter.write(nounV2 + " metadata should be uploaded in a TSV, CSV or Excel file with one row per " + nounV1.toLowerCase() + ". "); - PageFlowUtil.link("Download template", PageFlowUtil.urlProvider(NabUrls.class).getSampleXLSTemplateURL(_container, _protocol)).appendTo(oldWriter); - oldWriter.write("
"); - if (reshowFile != null) - { - PageConfig pageConfig = HttpView.currentPageConfig(); - PipeRoot pipelineRoot = PipelineService.get().findPipelineRoot(ctx.getContainer()); - String filePath = PageFlowUtil.filter(pipelineRoot.relativePath(reshowFile).replace('\\', '/')); - String updateInputFn = ""; - oldWriter.write(updateInputFn); - oldWriter.write("\n"); - oldWriter.write("\n"); - pageConfig.addHandler("optionPrevUpload", "change", "showMetadataPicker(!this.checked);"); - oldWriter.write("\n"); - oldWriter.write("\n"); - oldWriter.write("\n"); - oldWriter.write("\n"); - oldWriter.write("\n"); - pageConfig.addHandler("optionNewUpload", "change", "showMetadataPicker(this.checked);"); - oldWriter.write("\n"); - oldWriter.write("\n"); - oldWriter.write("\n"); - oldWriter.write("\n
Use the metadata that was already uploaded to the server
" + PageFlowUtil.filter(reshowFile.getName()) + "
"); - oldWriter.write("\nUpload a data file
"); - } - else - { - oldWriter.write("
" + - "" + - "" + - "
"); - } + PageConfig pageConfig = HttpView.currentPageConfig(); + PipeRoot pipelineRoot = PipelineService.get().findPipelineRoot(ctx.getContainer()); + String filePath = PageFlowUtil.filter(pipelineRoot.relativePath(reshowFile).replace('\\', '/')); + + SCRIPT( + JavaScriptFragment.unsafe(""" + function showMetadataPicker(showFilePicker) { + document.getElementById('previousMetadataFileName').style.display = (showFilePicker ? 'none' : 'block'); + document.getElementById('newMetadataFileName').style.display = (!showFilePicker ? 'none' : 'block'); + }""") + ).appendTo(out); + + TABLE( + TR( + TD(new InputBuilder<>().type("radio").id("optionPrevUpload").name(METADATA_PROVIDER_INPUT_NAME).value(METADATA_PROVIDER_OPTION_PREVUPLOAD).checked(true)), + TD("Use the metadata that was already uploaded to the server") + ), + TR( + TD(), + TD( + DIV( + id("previousMetadataFileName").at(style, "display:block"), + reshowFile.getName() + ) + ) + ), + TR( + TD( + new InputBuilder<>().type("hidden").name(METADATA_PREVUPLOAD_LOCATION).value(filePath), + new InputBuilder<>().type("radio").id("optionNewUpload").name(METADATA_PROVIDER_INPUT_NAME).value(METADATA_PROVIDER_OPTION_NEWUPLOAD) + ), + TD("Upload a data file") + ), + TR( + TD(), + TD( + DIV( + id("newMetadataFileName").at(style, "display:none"), + new InputBuilder<>().type("file").id(SAMPLE_FILE_INPUT_NAME).name(SAMPLE_FILE_INPUT_NAME).size(40).addStyle("border: none") + ) + ) + ) + ).appendTo(out); + + pageConfig.addHandler("optionPrevUpload", "change", "showMetadataPicker(!this.checked);"); + pageConfig.addHandler("optionNewUpload", "change", "showMetadataPicker(this.checked);"); + } + else + { + TABLE( + TR( + TD(), + TD( + new InputBuilder<>().type("hidden").name(METADATA_PROVIDER_INPUT_NAME).value(METADATA_PROVIDER_OPTION_NEWUPLOAD), + new InputBuilder<>().type("file").name(SAMPLE_FILE_INPUT_NAME).size(40).addStyle("border: none") + ) + ) + ).appendTo(out); } - } - catch (IOException e) - { - throw new RuntimeException(e); } } }); diff --git a/experiment/src/org/labkey/experiment/DataFileURLDisplayColumn.java b/experiment/src/org/labkey/experiment/DataFileURLDisplayColumn.java deleted file mode 100644 index d18d867c42d..00000000000 --- a/experiment/src/org/labkey/experiment/DataFileURLDisplayColumn.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2008-2019 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.experiment; - -import org.labkey.api.data.RenderContext; -import org.labkey.api.data.SimpleDisplayColumn; -import org.labkey.api.exp.api.ExpData; -import org.labkey.api.util.PageFlowUtil; -import org.labkey.api.view.ActionURL; -import org.labkey.api.writer.HtmlWriter; -import org.labkey.experiment.controllers.exp.ExperimentController; - -import java.io.IOException; -import java.io.Writer; - -/** - * User: jeckels - * Date: Sep 29, 2005 - */ -public class DataFileURLDisplayColumn extends SimpleDisplayColumn -{ - private final ExpData _data; - - public DataFileURLDisplayColumn(ExpData data) - { - super(); - setCaption("Data File"); - _data = data; - } - - @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException - { - String dataFileURL = _data.getDataFileUrl(); - if (dataFileURL == null || dataFileURL.trim().isEmpty()) - { - oldWriter.write("(Unknown)
\n"); - return; - } - - ActionURL contentURL = _data.findDataHandler().getContentURL(_data); - if (contentURL == null && _data.isFileOnDisk()) - { - contentURL = ExperimentController.ExperimentUrlsImpl.get().getShowFileURL(_data, false); - } - - if (contentURL != null) - { - oldWriter.write(""); - } - oldWriter.write(PageFlowUtil.filter(dataFileURL)); - oldWriter.write(""); - - if (!_data.isFileOnDisk()) - { - oldWriter.write(" (Not available on disk)\n"); - } - } -} diff --git a/experiment/src/org/labkey/experiment/ExperimentRunDisplayColumn.java b/experiment/src/org/labkey/experiment/ExperimentRunDisplayColumn.java index c770ce20303..c83554283d2 100644 --- a/experiment/src/org/labkey/experiment/ExperimentRunDisplayColumn.java +++ b/experiment/src/org/labkey/experiment/ExperimentRunDisplayColumn.java @@ -18,17 +18,11 @@ import org.labkey.api.data.RenderContext; import org.labkey.api.data.SimpleDisplayColumn; import org.labkey.api.exp.api.ExpRun; +import org.labkey.api.util.Link.LinkBuilder; import org.labkey.api.view.ActionURL; import org.labkey.api.writer.HtmlWriter; import org.labkey.experiment.controllers.exp.ExperimentController; -import java.io.IOException; -import java.io.Writer; - -/** - * User: jeckels - * Date: Oct 19, 2005 - */ public class ExperimentRunDisplayColumn extends SimpleDisplayColumn { private ExpRun _run; @@ -45,16 +39,17 @@ public ExperimentRunDisplayColumn(ExpRun run, String name) } @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException + public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) { if (_run == null) { - oldWriter.write("(Unknown)"); + out.write("(Unknown)"); } else { ActionURL url = ExperimentController.getRunGraphURL(ctx.getContainer(), _run.getRowId()); - oldWriter.write("" + _run.getName() + ""); + + out.write(new LinkBuilder(_run.getName()).href(url).clearClasses()); } } } diff --git a/experiment/src/org/labkey/experiment/LineageGraphDisplayColumn.java b/experiment/src/org/labkey/experiment/LineageGraphDisplayColumn.java index 9965240d6f7..a3e7f30fb0f 100644 --- a/experiment/src/org/labkey/experiment/LineageGraphDisplayColumn.java +++ b/experiment/src/org/labkey/experiment/LineageGraphDisplayColumn.java @@ -22,22 +22,16 @@ import org.labkey.api.exp.api.ExpObject; import org.labkey.api.exp.api.ExpProtocolApplication; import org.labkey.api.exp.api.ExpRun; +import org.labkey.api.util.Link.LinkBuilder; import org.labkey.api.view.ActionURL; import org.labkey.api.writer.HtmlWriter; import org.labkey.experiment.controllers.exp.ExperimentController; -import java.io.IOException; -import java.io.Writer; - -/** - * User: jeckels - * Date: Oct 19, 2005 - */ public class LineageGraphDisplayColumn extends SimpleDisplayColumn { - private Integer _runId; - private String _focus; - private String _linkText; + private final Integer _runId; + private final String _focus; + private final String _linkText; public LineageGraphDisplayColumn(ExpMaterial material, ExpRun run) { @@ -56,20 +50,19 @@ public LineageGraphDisplayColumn(ExpProtocolApplication app, ExpRun run) private LineageGraphDisplayColumn(String typeCode, ExpObject object, ExpRun run) { - _linkText = "Lineage for "; _focus = typeCode + object.getRowId(); - _linkText += object.getName(); + _linkText = "Lineage for " + object.getName(); _runId = run == null ? null : run.getRowId(); setCaption("Lineage Graph"); } @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException + public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) { if (_runId == null || _focus == null) { - oldWriter.write("(Unknown)"); + out.write("(Unknown)"); } else { @@ -77,7 +70,8 @@ public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlW url.addParameter("rowId", Integer.toString(_runId)); url.addParameter("detail", "true"); url.addParameter("focus", _focus); - oldWriter.write("" + _linkText + ""); + + out.write(new LinkBuilder(_linkText).href(url).clearClasses()); } } } diff --git a/experiment/src/org/labkey/experiment/ProtocolApplicationDisplayColumn.java b/experiment/src/org/labkey/experiment/ProtocolApplicationDisplayColumn.java index f94f32d7c50..d3ef28dfa23 100644 --- a/experiment/src/org/labkey/experiment/ProtocolApplicationDisplayColumn.java +++ b/experiment/src/org/labkey/experiment/ProtocolApplicationDisplayColumn.java @@ -18,20 +18,14 @@ import org.labkey.api.data.RenderContext; import org.labkey.api.data.SimpleDisplayColumn; import org.labkey.api.exp.api.ExpProtocolApplication; +import org.labkey.api.util.Link.LinkBuilder; import org.labkey.api.view.ActionURL; import org.labkey.api.writer.HtmlWriter; import org.labkey.experiment.controllers.exp.ExperimentController; -import java.io.IOException; -import java.io.Writer; - -/** - * User: jeckels - * Date: Oct 19, 2005 - */ public class ProtocolApplicationDisplayColumn extends SimpleDisplayColumn { - private ExpProtocolApplication _protocolApplication; + private final ExpProtocolApplication _protocolApplication; public ProtocolApplicationDisplayColumn(ExpProtocolApplication protocolApplication) { @@ -45,16 +39,16 @@ public ProtocolApplicationDisplayColumn(ExpProtocolApplication protocolApplicati } @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException + public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) { if (_protocolApplication == null) { - oldWriter.write("(Unknown)"); + out.write("(Unknown)"); } else { ActionURL url = ExperimentController.getShowApplicationURL(ctx.getContainer(), _protocolApplication.getRowId()); - oldWriter.write("" + _protocolApplication.getName() + ""); + out.write(new LinkBuilder(_protocolApplication.getName()).href(url).clearClasses()); } } } diff --git a/experiment/src/org/labkey/experiment/ProtocolDisplayColumn.java b/experiment/src/org/labkey/experiment/ProtocolDisplayColumn.java index da593a22259..456cfa4b503 100644 --- a/experiment/src/org/labkey/experiment/ProtocolDisplayColumn.java +++ b/experiment/src/org/labkey/experiment/ProtocolDisplayColumn.java @@ -18,20 +18,14 @@ import org.labkey.api.data.RenderContext; import org.labkey.api.data.SimpleDisplayColumn; import org.labkey.api.exp.api.ExpProtocol; +import org.labkey.api.util.Link.LinkBuilder; import org.labkey.api.view.ActionURL; import org.labkey.api.writer.HtmlWriter; import org.labkey.experiment.controllers.exp.ExperimentController; -import java.io.IOException; -import java.io.Writer; - -/** - * User: jeckels - * Date: Oct 19, 2005 - */ public class ProtocolDisplayColumn extends SimpleDisplayColumn { - private ExpProtocol _protocol; + private final ExpProtocol _protocol; public ProtocolDisplayColumn(ExpProtocol protocol) { @@ -45,18 +39,18 @@ public ProtocolDisplayColumn(ExpProtocol protocol, String name) } @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException + public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) { if (_protocol == null) { - oldWriter.write("(Unknown)"); + out.write("(Unknown)"); } else { ActionURL url = new ActionURL(ExperimentController.ProtocolDetailsAction.class, ctx.getContainer()); url.addParameter("rowId", Integer.toString(_protocol.getRowId())); - oldWriter.write("" + _protocol.getName() + ""); + + out.write(new LinkBuilder(_protocol.getName()).href(url).clearClasses()); } } - } diff --git a/experiment/src/org/labkey/experiment/SampleTypeDisplayColumn.java b/experiment/src/org/labkey/experiment/SampleTypeDisplayColumn.java index 6ecba386f62..2ee12c8e77a 100644 --- a/experiment/src/org/labkey/experiment/SampleTypeDisplayColumn.java +++ b/experiment/src/org/labkey/experiment/SampleTypeDisplayColumn.java @@ -20,18 +20,11 @@ import org.labkey.api.data.SimpleDisplayColumn; import org.labkey.api.exp.api.ExpMaterial; import org.labkey.api.exp.api.ExpSampleType; -import org.labkey.api.util.PageFlowUtil; +import org.labkey.api.util.Link.LinkBuilder; import org.labkey.api.view.ActionURL; import org.labkey.api.writer.HtmlWriter; import org.labkey.experiment.controllers.exp.ExperimentController; -import java.io.IOException; -import java.io.Writer; - -/** - * User: jeckels - * Date: Oct 4, 2007 - */ public class SampleTypeDisplayColumn extends SimpleDisplayColumn { private final ExpMaterial _material; @@ -43,19 +36,19 @@ public SampleTypeDisplayColumn(ExpMaterial material) } @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException + public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) { ExpSampleType st = _material.getSampleType(); if (st == null) { - oldWriter.write("Not a member of a sample type"); + out.write("Not a member of a sample type"); } else { ActionURL url = new ActionURL(ExperimentController.ShowSampleTypeAction.class, st.getContainer()); url.addParameter("rowId", Integer.toString(st.getRowId())); - oldWriter.write("" + PageFlowUtil.filter(st.getName()) + ""); + out.write(new LinkBuilder(st.getName()).href(url).clearClasses()); } } } diff --git a/experiment/src/org/labkey/experiment/lineage/LineageDisplayColumn.java b/experiment/src/org/labkey/experiment/lineage/LineageDisplayColumn.java index b594fc0b1de..e74b3303da5 100644 --- a/experiment/src/org/labkey/experiment/lineage/LineageDisplayColumn.java +++ b/experiment/src/org/labkey/experiment/lineage/LineageDisplayColumn.java @@ -235,7 +235,7 @@ public boolean isEditable() } @Override - public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object value) + public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) { } diff --git a/issues/src/org/labkey/issue/query/IssuesListDefTable.java b/issues/src/org/labkey/issue/query/IssuesListDefTable.java index 11987c828a9..c7bc870a484 100644 --- a/issues/src/org/labkey/issue/query/IssuesListDefTable.java +++ b/issues/src/org/labkey/issue/query/IssuesListDefTable.java @@ -51,8 +51,9 @@ import org.labkey.api.security.permissions.Permission; import org.labkey.api.security.permissions.ReadPermission; import org.labkey.api.util.Link; -import org.labkey.api.util.PageFlowUtil; import org.labkey.api.util.Pair; +import org.labkey.api.util.element.Option.OptionBuilder; +import org.labkey.api.util.element.Select.SelectBuilder; import org.labkey.api.view.ActionURL; import org.labkey.api.writer.HtmlWriter; import org.labkey.issue.IssuesController; @@ -61,13 +62,12 @@ import org.labkey.issue.model.IssueListDef; import org.labkey.issue.model.IssueManager; -import java.io.IOException; -import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Stream; public class IssuesListDefTable extends FilteredTable { @@ -338,30 +338,19 @@ public MultiValueInputColumn(ColumnInfo col, @NotNull List> } @Override - public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object val) throws IOException + public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object val) { String formFieldName = ctx.getForm().getFormFieldName(getColumnInfo()); - oldWriter.write("\n"); + new SelectBuilder() + .name(formFieldName) + .addOptions( + _values.isEmpty() ? + Stream.of("") : + _values.stream() + .map(pair -> new OptionBuilder(pair.second, pair.first)) + ) + .appendTo(out); } @Override diff --git a/mothership/src/org/labkey/mothership/AssignedToDisplayColumn.java b/mothership/src/org/labkey/mothership/AssignedToDisplayColumn.java index 3cc560f5672..80f9c1a26b4 100644 --- a/mothership/src/org/labkey/mothership/AssignedToDisplayColumn.java +++ b/mothership/src/org/labkey/mothership/AssignedToDisplayColumn.java @@ -21,11 +21,10 @@ import org.labkey.api.data.DataColumn; import org.labkey.api.data.RenderContext; import org.labkey.api.security.User; -import org.labkey.api.util.PageFlowUtil; +import org.labkey.api.util.element.Option.OptionBuilder; +import org.labkey.api.util.element.Select.SelectBuilder; import org.labkey.api.writer.HtmlWriter; -import java.io.IOException; -import java.io.Writer; import java.util.List; public class AssignedToDisplayColumn extends DataColumn @@ -40,29 +39,18 @@ public AssignedToDisplayColumn(ColumnInfo col, Container c) } @Override - public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object value) throws IOException + public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) { List list = MothershipManager.get().getAssignedToList(_container); - oldWriter.write(""); + new SelectBuilder() + .name(getColumnInfo().getPropertyName()) + .addOption("") + .addOptions( + list.stream() + .map(user -> new OptionBuilder(user.getDisplayName(ctx.getViewContext().getUser()), user.getUserId())) + ) + .selected(value) + .appendTo(out); } } diff --git a/mothership/src/org/labkey/mothership/CreateIssueDisplayColumn.java b/mothership/src/org/labkey/mothership/CreateIssueDisplayColumn.java index d78c9e14e46..d46e8acccc2 100644 --- a/mothership/src/org/labkey/mothership/CreateIssueDisplayColumn.java +++ b/mothership/src/org/labkey/mothership/CreateIssueDisplayColumn.java @@ -39,14 +39,14 @@ public CreateIssueDisplayColumn(ColumnInfo column, ActionButton saveButton) } @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException + public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) { - _saveButton.render(ctx, oldWriter); - oldWriter.write("\t"); + _saveButton.render(ctx, out); + out.write("\t"); PageFlowUtil.button("Create Issue") .onClick("document.forms.CreateIssue.elements['assignedTo'].value = document.forms[" + PageFlowUtil.jsString(ctx.getCurrentRegion().getFormId()) + "].elements['assignedTo'].value; document.forms.CreateIssue.submit();") - .appendTo(oldWriter); + .appendTo(out); } } diff --git a/mothership/src/org/labkey/mothership/MothershipManager.java b/mothership/src/org/labkey/mothership/MothershipManager.java index e85a0076073..f5a9c22f104 100644 --- a/mothership/src/org/labkey/mothership/MothershipManager.java +++ b/mothership/src/org/labkey/mothership/MothershipManager.java @@ -17,7 +17,6 @@ package org.labkey.mothership; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; @@ -54,10 +53,6 @@ import static org.labkey.api.security.UserManager.USER_DISPLAY_NAME_COMPARATOR; -/** - * User: jeckels - * Date: Apr 20, 2006 - */ public class MothershipManager { private static final MothershipManager INSTANCE = new MothershipManager(); diff --git a/pipeline/src/org/labkey/pipeline/status/FileDisplayColumn.java b/pipeline/src/org/labkey/pipeline/status/FileDisplayColumn.java index e9af8481f6b..2a4269e7ae0 100644 --- a/pipeline/src/org/labkey/pipeline/status/FileDisplayColumn.java +++ b/pipeline/src/org/labkey/pipeline/status/FileDisplayColumn.java @@ -23,12 +23,12 @@ import org.labkey.api.pipeline.PipelineProvider; import org.labkey.api.pipeline.PipelineService; import org.labkey.api.util.FileUtil; +import org.labkey.api.util.HtmlString; import org.labkey.api.util.NetworkDrive; import org.labkey.api.util.PageFlowUtil; import org.labkey.api.writer.HtmlWriter; import java.io.IOException; -import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; @@ -42,12 +42,11 @@ public class FileDisplayColumn extends SimpleDisplayColumn { public FileDisplayColumn() { - super(); setCaption("Files"); } @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException + public void renderDetailsCellContents(RenderContext ctx, HtmlWriter out) { List files = null; @@ -67,7 +66,7 @@ public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlW if (files == null || files.isEmpty()) { - oldWriter.write(" "); + out.write(HtmlString.NBSP); } else { @@ -75,24 +74,22 @@ public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlW { // make sure the files can be open for read String fileName = file.getFileName().toString(); + if (Files.isReadable(file)) { - oldWriter.write(""); - oldWriter.write(PageFlowUtil.filter(fileName)); - oldWriter.write("\n"); - - oldWriter.write("  "); - PageFlowUtil.link("view").href(StatusController.urlShowFile(ctx.getContainer(), rowIdI.intValue(), fileName, false)).appendTo(oldWriter); - PageFlowUtil.link("download").href(StatusController.urlShowFile(ctx.getContainer(), rowIdI.intValue(), fileName, true)).appendTo(oldWriter); - oldWriter.write("
\n"); + out.write(PageFlowUtil.link(fileName).href(StatusController.urlShowFile(ctx.getContainer(), rowIdI.intValue(), fileName, false))); + out.write(HtmlString.NBSP); + out.write(HtmlString.NBSP); + out.write(PageFlowUtil.link("view").href(StatusController.urlShowFile(ctx.getContainer(), rowIdI.intValue(), fileName, false))); + out.write(PageFlowUtil.link("download").href(StatusController.urlShowFile(ctx.getContainer(), rowIdI.intValue(), fileName, true))); } else { - oldWriter.write(PageFlowUtil.filter(fileName)); - oldWriter.write("
\n"); + out.write(fileName); } + + out.write(HtmlString.BR); + out.write("\n"); } } } diff --git a/pipeline/src/org/labkey/pipeline/status/JobDisplayColumn.java b/pipeline/src/org/labkey/pipeline/status/JobDisplayColumn.java deleted file mode 100644 index 5c6351ec42f..00000000000 --- a/pipeline/src/org/labkey/pipeline/status/JobDisplayColumn.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2008-2019 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.pipeline.status; - -import org.labkey.api.data.RenderContext; -import org.labkey.api.data.SimpleDisplayColumn; -import org.labkey.api.pipeline.PipelineStatusFile; -import org.labkey.api.util.PageFlowUtil; -import org.labkey.api.writer.HtmlWriter; -import org.labkey.pipeline.api.PipelineStatusFileImpl; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import static org.labkey.pipeline.api.PipelineStatusManager.getJobStatusFile; -import static org.labkey.pipeline.api.PipelineStatusManager.getSplitStatusFiles; - -/** - * SplitDisplayColumn class - *

- * Created: Oct 25, 2005 - * - * @author bmaclean - */ -public class JobDisplayColumn extends SimpleDisplayColumn -{ - private boolean _split; - private List _jobStatus; - - public JobDisplayColumn(boolean split) - { - super(); - _split = split; - if (_split) - setCaption("Split jobs"); - else - setCaption("Join job"); - } - - @Override - public boolean isVisible(RenderContext ctx) - { - return !getJobStatus(ctx).isEmpty(); - } - - @Override - public void renderDetailsCellContents(RenderContext ctx, Writer oldWriter, HtmlWriter out) throws IOException - { - if (_jobStatus == null || _jobStatus.isEmpty()) - oldWriter.write(" "); - else - { - int rowIndex = 0; - oldWriter.write("\n" + - "\n" + - "\n" + - " \n" + - " \n" + - ""); - for (PipelineStatusFile sf : _jobStatus) - { - if (rowIndex++ % 2 == 0) - oldWriter.write(""); - else - oldWriter.write(""); - - oldWriter.write(""); - oldWriter.write(""); - oldWriter.write("\n"); - } - oldWriter.write("
Status
Description
"); - oldWriter.write(PageFlowUtil.filter(sf.getStatus())); - oldWriter.write(""); - oldWriter.write(PageFlowUtil.filter(sf.getDescription())); - oldWriter.write("
\n"); - } - } - - public List getJobStatus(RenderContext ctx) - { - if (_jobStatus == null) - { - if (_split) - { - String jobId = (String) ctx.get("Job"); - if (jobId != null) - { - // If we're being rendered from the Admin Console, we won't be in the right container, - // so don't specify one - _jobStatus = getSplitStatusFiles(jobId); - } - } - else if (ctx.get("JobParent") != null) - { - PipelineStatusFileImpl parent = getJobStatusFile((String) ctx.get("JobParent")); - if (parent != null) - { - _jobStatus = Collections.singletonList(parent); - } - } - if (_jobStatus == null) - _jobStatus = Collections.emptyList(); - // Make a copy of the immutable list so we can sort as needed - _jobStatus = new ArrayList<>(_jobStatus); - - _jobStatus.sort(Comparator.comparing(PipelineStatusFile::getDescription, String.CASE_INSENSITIVE_ORDER)); - } - - return _jobStatus; - } -} diff --git a/study/api-src/org/labkey/api/study/InsertUpdateAction.java b/study/api-src/org/labkey/api/study/InsertUpdateAction.java index def29455e7f..00554a6f2f9 100644 --- a/study/api-src/org/labkey/api/study/InsertUpdateAction.java +++ b/study/api-src/org/labkey/api/study/InsertUpdateAction.java @@ -52,6 +52,7 @@ import org.labkey.api.study.model.CohortService; import org.labkey.api.util.PageFlowUtil; import org.labkey.api.util.URLHelper; +import org.labkey.api.util.element.Select.SelectBuilder; import org.labkey.api.view.ActionURL; import org.labkey.api.view.DataView; import org.labkey.api.view.InsertView; @@ -66,8 +67,6 @@ import org.springframework.validation.Errors; import org.springframework.web.servlet.ModelAndView; -import java.io.IOException; -import java.io.Writer; import java.sql.SQLException; import java.util.Collection; import java.util.Collections; @@ -142,23 +141,22 @@ public ModelAndView getView(Form form, boolean reshow, BindException errors) thr cohortCol.setDisplayColumnFactory(colInfo -> new DataColumn(colInfo) { @Override - public void renderInputHtml(RenderContext ctx, Writer oldWriter, HtmlWriter out, Object value) throws IOException + public void renderInputHtml(RenderContext ctx, HtmlWriter out, Object value) { boolean disabledInput = isDisabledInput(); String formFieldName = ctx.getForm().getFormFieldName(getBoundColumn()); - oldWriter.write(""); + builder.addOption(""); + + builder.addOptions(cohorts.stream().map(StudyEntity::getLabel)) + .selected(value) + .appendTo(out); } }); }