From 230df95da49720e4d3ad2bde9da9d4b0eca05c62 Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Tue, 13 Dec 2022 10:40:18 +0100 Subject: [PATCH 1/4] #3630 - Export of single document fails when username is too short - Pad temp file names to three char prefix if necessary --- .../ukp/clarin/webanno/api/format/FormatSupport.java | 7 +++++-- .../project/export/ProjectExportServiceImpl.java | 6 +++++- .../webapp/remoteapi/LegacyRemoteApiController.java | 8 +++++--- .../webapp/remoteapi/aero/AeroRemoteApiController.java | 2 +- .../inception/support/io/FileUploadDownloadHelper.java | 3 +-- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/inception/inception-api-formats/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/format/FormatSupport.java b/inception/inception-api-formats/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/format/FormatSupport.java index 5c8965748e1..867fe469f2e 100644 --- a/inception/inception-api-formats/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/format/FormatSupport.java +++ b/inception/inception-api-formats/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/format/FormatSupport.java @@ -34,6 +34,7 @@ import java.util.Optional; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.uima.analysis_engine.AnalysisEngine; import org.apache.uima.analysis_engine.AnalysisEngineDescription; import org.apache.uima.analysis_engine.AnalysisEngineProcessException; @@ -196,8 +197,10 @@ default File write(SourceDocument aDocument, CAS aCas, File aTargetFolder, } // If the writer produced only a single file, then that is the result - File exportFile = createTempFile( - FilenameUtils.getBaseName(aTargetFolder.listFiles()[0].getName()), + String filename = FilenameUtils.getBaseName(aTargetFolder.listFiles()[0].getName()); + // temp-file prefix must be at least 3 chars + filename = StringUtils.rightPad(filename, 3, "_"); + File exportFile = createTempFile(filename, "." + FilenameUtils.getExtension(aTargetFolder.listFiles()[0].getName())); // File exportFile = new File(aTargetFolder.getParent(), // aTargetFolder.listFiles()[0].getName()); diff --git a/inception/inception-project-export/src/main/java/de/tudarmstadt/ukp/inception/project/export/ProjectExportServiceImpl.java b/inception/inception-project-export/src/main/java/de/tudarmstadt/ukp/inception/project/export/ProjectExportServiceImpl.java index ed4284ebca8..8080c25f41a 100644 --- a/inception/inception-project-export/src/main/java/de/tudarmstadt/ukp/inception/project/export/ProjectExportServiceImpl.java +++ b/inception/inception-project-export/src/main/java/de/tudarmstadt/ukp/inception/project/export/ProjectExportServiceImpl.java @@ -52,6 +52,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; @@ -171,7 +172,10 @@ public void onContextRefreshedEvent(ContextRefreshedEvent aEvent) public File exportProject(FullProjectExportRequest aRequest, ProjectExportTaskMonitor aMonitor) throws ProjectExportException, IOException, InterruptedException { - File projectZipFile = File.createTempFile(aRequest.getProject().getSlug(), ".zip"); + String filename = aRequest.getProject().getSlug(); + // temp-file prefix must be at least 3 chars + filename = StringUtils.rightPad(filename, 3, "_"); + File projectZipFile = File.createTempFile(filename, ".zip"); boolean success = false; try { exportProject(aRequest, aMonitor, projectZipFile); diff --git a/inception/inception-remote/src/main/java/de/tudarmstadt/ukp/clarin/webanno/webapp/remoteapi/LegacyRemoteApiController.java b/inception/inception-remote/src/main/java/de/tudarmstadt/ukp/clarin/webanno/webapp/remoteapi/LegacyRemoteApiController.java index d064e0ff7b3..86da546e5ee 100644 --- a/inception/inception-remote/src/main/java/de/tudarmstadt/ukp/clarin/webanno/webapp/remoteapi/LegacyRemoteApiController.java +++ b/inception/inception-remote/src/main/java/de/tudarmstadt/ukp/clarin/webanno/webapp/remoteapi/LegacyRemoteApiController.java @@ -182,7 +182,10 @@ public ResponseEntity projectCreate( // // If the current filename does not start with "." and is in the root folder of the ZIP, // import it as a source document - File zipFile = File.createTempFile(aFile.getOriginalFilename(), ".zip"); + String filename = aFile.getOriginalFilename(); + // temp-file prefix must be at least 3 chars + filename = StringUtils.rightPad(filename, 3, "_"); + File zipFile = File.createTempFile(filename, ".zip"); aFile.transferTo(zipFile); ZipFile zip = new ZipFile(zipFile); @@ -191,8 +194,7 @@ public ResponseEntity projectCreate( // ZipEntry entry = (ZipEntry) zipEnumerate.nextElement(); // If it is the zip name, ignore it - if ((FilenameUtils.removeExtension(aFile.getOriginalFilename()) + "/") - .equals(entry.toString())) { + if ((FilenameUtils.removeExtension(filename) + "/").equals(entry.toString())) { continue; } // IF the current filename is META-INF/webanno/source-meta-data.properties store it as diff --git a/inception/inception-remote/src/main/java/de/tudarmstadt/ukp/clarin/webanno/webapp/remoteapi/aero/AeroRemoteApiController.java b/inception/inception-remote/src/main/java/de/tudarmstadt/ukp/clarin/webanno/webapp/remoteapi/aero/AeroRemoteApiController.java index 3a68debc348..737d2d02529 100644 --- a/inception/inception-remote/src/main/java/de/tudarmstadt/ukp/clarin/webanno/webapp/remoteapi/aero/AeroRemoteApiController.java +++ b/inception/inception-remote/src/main/java/de/tudarmstadt/ukp/clarin/webanno/webapp/remoteapi/aero/AeroRemoteApiController.java @@ -400,7 +400,7 @@ public ResponseEntity> projectImport( userRepository.isAdministrator(user)); Project importedProject; - File tempFile = File.createTempFile("webanno-training", null); + File tempFile = File.createTempFile("inception-project-import", null); try (InputStream is = new BufferedInputStream(aFile.getInputStream()); OutputStream os = new FileOutputStream(tempFile);) { if (!ZipUtils.isZipStream(is)) { diff --git a/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/io/FileUploadDownloadHelper.java b/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/io/FileUploadDownloadHelper.java index ce17e48d87a..ab1ea3ac974 100644 --- a/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/io/FileUploadDownloadHelper.java +++ b/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/io/FileUploadDownloadHelper.java @@ -36,13 +36,12 @@ public class FileUploadDownloadHelper { + private static final String INCEPTION_TMP_FILE_PREFIX = "inception_file"; private final Logger log = LoggerFactory.getLogger(getClass()); private final IFileCleaner fileTracker; - private final String INCEPTION_TMP_FILE_PREFIX = "inception_file"; - public FileUploadDownloadHelper(Application application) { fileTracker = application.getResourceSettings().getFileCleaner(); From 03399677c25c640343e2782365b9c9fca32510b0 Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Tue, 13 Dec 2022 11:16:07 +0100 Subject: [PATCH 2/4] #3609 - Feature editors do not show annotations in locked documents for multilabel String features - Use a non-lazy multi-select when the input is disabled because the lazy multi-select has this bug not showing values when disabled --- .../MultiSelectTextFeatureEditor.java | 6 +- .../ui/kb/feature/ConceptFeatureEditor.java | 2 +- .../ConceptFeatureEditor_ImplBase.java | 3 +- .../MultiValueConceptFeatureEditor.java | 78 +++++++++++++++++-- 4 files changed, 75 insertions(+), 14 deletions(-) diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/multistring/MultiSelectTextFeatureEditor.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/multistring/MultiSelectTextFeatureEditor.java index f7d9d6c64f4..983d9c3e747 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/multistring/MultiSelectTextFeatureEditor.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/multistring/MultiSelectTextFeatureEditor.java @@ -78,10 +78,6 @@ public MultiSelectTextFeatureEditor(String aId, MarkupContainer aOwner, add(new ConstraintsInUseIndicator(CID_TEXT_INDICATOR, getModel())); } - /** - * Hides feature if "Hide un-constraint feature" is enabled and constraint rules are applied and - * feature doesn't match any constraint rule - */ @SuppressWarnings("unchecked") @Override public void onConfigure() @@ -94,6 +90,8 @@ public void onConfigure() field = (FormComponent) field.replaceWith(createInput()); } + // Hides feature if "Hide un-constraint feature" is enabled and constraint rules are applied + // and feature doesn't match any constraint rule // if enabled and constraints rule execution returns anything other than green var featState = getModelObject(); setVisible(!featState.feature.isHideUnconstraintFeature() || // diff --git a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor.java b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor.java index 1abded24240..b676084136f 100644 --- a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor.java +++ b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor.java @@ -80,7 +80,7 @@ public class ConceptFeatureEditor public ConceptFeatureEditor(String aId, MarkupContainer aItem, IModel aModel, IModel aStateModel, AnnotationActionHandler aHandler) { - super(aId, aItem, aModel, aStateModel, aHandler); + super(aId, aItem, aModel); AnnotationFeature feat = getModelObject().feature; ConceptFeatureTraits traits = readFeatureTraits(feat); diff --git a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor_ImplBase.java b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor_ImplBase.java index d999109ddfd..68e0dbec4af 100644 --- a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor_ImplBase.java +++ b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor_ImplBase.java @@ -75,8 +75,7 @@ public abstract class ConceptFeatureEditor_ImplBase private @SpringBean EntityLinkingProperties entityLinkingProperties; public ConceptFeatureEditor_ImplBase(String aId, MarkupContainer aItem, - IModel aModel, IModel aStateModel, - AnnotationActionHandler aHandler) + IModel aModel) { super(aId, aItem, new CompoundPropertyModel<>(aModel)); diff --git a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/MultiValueConceptFeatureEditor.java b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/MultiValueConceptFeatureEditor.java index 7dd5d52801a..b91b6667b22 100644 --- a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/MultiValueConceptFeatureEditor.java +++ b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/MultiValueConceptFeatureEditor.java @@ -46,20 +46,86 @@ public class MultiValueConceptFeatureEditor { private static final long serialVersionUID = -8326017157405023711L; + private static final String CID_VALUE = "value"; + private @SpringBean FeatureSupportRegistry featureSupportRegistry; - private MultiSelect focusComponent; + private final AnnotationActionHandler handler; + private final IModel stateModel; + + private FormComponent> focusComponent; public MultiValueConceptFeatureEditor(String aId, MarkupContainer aItem, IModel aModel, IModel aStateModel, AnnotationActionHandler aHandler) { - super(aId, aItem, aModel, aStateModel, aHandler); + super(aId, aItem, aModel); - focusComponent = new KBHandleMultiSelect("value", aHandler, aStateModel); + handler = aHandler; + stateModel = aStateModel; + + focusComponent = createInput(); add(focusComponent); } + @SuppressWarnings("unchecked") + @Override + public void onConfigure() + { + super.onConfigure(); + + // Workaround for https://github.com/sebfz1/wicket-jquery-ui/issues/352 + if ((isEnabledInHierarchy() && !(focusComponent instanceof MultiSelect)) + || !isEnabledInHierarchy() && (focusComponent instanceof MultiSelect)) { + focusComponent = (FormComponent>) focusComponent + .replaceWith(createInput()); + } + } + + private FormComponent> createInput() + { + if (isEnabledInHierarchy()) { + return createEditableInput(); + } + else { + return createReadOnlyInput(); + } + } + + private FormComponent> createEditableInput() + { + return new KBHandleMultiSelect(CID_VALUE, handler, stateModel); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private FormComponent> createReadOnlyInput() + { + var input = new com.googlecode.wicket.kendo.ui.form.multiselect. // + MultiSelect(CID_VALUE) + { + private static final long serialVersionUID = 1L; + + @Override + public void onConfigure(JQueryBehavior aBehavior) + { + super.onConfigure(aBehavior); + styleMultiSelect(aBehavior); + } + }; + input.setChoiceRenderer( + new org.apache.wicket.markup.html.form.ChoiceRenderer<>("uiLabel", "identifier")); + input.setChoices(() -> input.getModel().map(ArrayList::new).getObject()); + return (FormComponent) input; + } + + private void styleMultiSelect(JQueryBehavior aBehavior) + { + aBehavior.setOption("autoWidth", true); + aBehavior.setOption("animation", false); + aBehavior.setOption("delay", 250); + aBehavior.setOption("height", 300); + } + @Override public FormComponent> getFocusComponent() { @@ -113,10 +179,8 @@ public void onConfigure(JQueryBehavior aBehavior) { super.onConfigure(aBehavior); - aBehavior.setOption("autoWidth", true); - aBehavior.setOption("animation", false); - aBehavior.setOption("delay", 250); - aBehavior.setOption("height", 300); + styleMultiSelect(aBehavior); + // These three settings should avoid a query when simply clicking into the multiselect // field, but they seem to have no effect // aBehavior.setOption("autoBind", false); From d276802705d1d9f4b533f6b134933446214f66eb Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Tue, 13 Dec 2022 11:20:12 +0100 Subject: [PATCH 3/4] #3630 - Export of single document fails when username is too short - Fix dependencies --- inception/inception-api-formats/pom.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/inception/inception-api-formats/pom.xml b/inception/inception-api-formats/pom.xml index eeb56ed4cb9..bd55e40a78b 100644 --- a/inception/inception-api-formats/pom.xml +++ b/inception/inception-api-formats/pom.xml @@ -57,5 +57,9 @@ commons-io commons-io + + org.apache.commons + commons-lang3 + - \ No newline at end of file + From 342f77505183b32b4fb41ee8c784bd64939a03b0 Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Tue, 13 Dec 2022 12:02:01 +0100 Subject: [PATCH 4/4] #3634 - Dropdowns look odd - Fixed style - Includes some fix backports from main --- .../misc/ReorderableTagAutoCompleteField.java | 24 ++--- .../bootstrap/inception-feature-editors.scss | 63 ++++++------ .../src/main/ts/bootstrap/shim-kendo.scss | 36 +++++-- .../webanno/support/StyledComboBox.java | 9 +- .../support/kendo/KendoStyleUtils.java | 96 +++++++++++++++++++ .../ui/kb/feature/ConceptFeatureEditor.html | 2 +- .../ui/kb/feature/KBHandleTemplate.java | 30 +++--- .../KnowledgeBaseItemAutoCompleteField.java | 37 +++---- 8 files changed, 196 insertions(+), 101 deletions(-) create mode 100644 inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/kendo/KendoStyleUtils.java diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/misc/ReorderableTagAutoCompleteField.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/misc/ReorderableTagAutoCompleteField.java index f166b45af58..2eccf438efc 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/misc/ReorderableTagAutoCompleteField.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/misc/ReorderableTagAutoCompleteField.java @@ -33,6 +33,7 @@ import de.tudarmstadt.ukp.clarin.webanno.model.Tag; import de.tudarmstadt.ukp.inception.annotation.feature.string.KendoChoiceDescriptionScriptReference; import de.tudarmstadt.ukp.inception.rendering.editorstate.FeatureState; +import de.tudarmstadt.ukp.inception.support.kendo.KendoStyleUtils; public class ReorderableTagAutoCompleteField extends AutoCompleteTextField @@ -71,21 +72,20 @@ protected List getChoices(String aTerm) } @Override - public void onConfigure(JQueryBehavior behavior) + public void onConfigure(JQueryBehavior aBehavior) { - super.onConfigure(behavior); + super.onConfigure(aBehavior); - behavior.setOption("delay", 500); - behavior.setOption("animation", false); - behavior.setOption("footerTemplate", + aBehavior.setOption("delay", 500); + aBehavior.setOption("animation", false); + aBehavior.setOption("footerTemplate", Options.asString("#: instance.dataSource.total() # items found")); - // Prevent scrolling action from closing the dropdown while the focus is on the - // input field - behavior.setOption("close", - String.join(" ", "function(e) {", - " if (document.activeElement == e.sender.element[0]) {", - " e.preventDefault();" + " }", "}")); - behavior.setOption("select", " function (e) { this.trigger('change'); }"); + + KendoStyleUtils.keepDropdownVisibleWhenScrolling(aBehavior); + KendoStyleUtils.autoDropdownHeight(aBehavior); + // KendoStyleUtils.autoDropdownWidth(aBehavior); + + aBehavior.setOption("select", " function (e) { this.trigger('change'); }"); } /* diff --git a/inception/inception-bootstrap/src/main/ts/bootstrap/inception-feature-editors.scss b/inception/inception-bootstrap/src/main/ts/bootstrap/inception-feature-editors.scss index a4ba794ddcf..b66b6a4c430 100644 --- a/inception/inception-bootstrap/src/main/ts/bootstrap/inception-feature-editors.scss +++ b/inception/inception-bootstrap/src/main/ts/bootstrap/inception-feature-editors.scss @@ -15,8 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - .feature-editor-label { @include media-breakpoint-up(sm) { @include make-col(3); @@ -68,37 +66,34 @@ } } -.k-item .item-title { - font-weight: bolder; -} - -.k-item .item-title .badge { - font-size: 8px; -/* background-color: #eeeeee; */ -} - -.k-list-container > .k-footer { - background-color: #eeeeee; - border-top: 1px solid #bbb; - padding: 3px 10px; -} - -.k-item .item-rank { - font-weight: lighter; -} - -.k-item .item-identifier { - font-size: 85%; - line-height: normal; - font-style: italic; - padding-left: 10px; -} - -.k-item .item-description { - font-size: 85%; - font-weight: lighter; - white-space: normal; - line-height: normal; - padding-left: 10px; +// Cannot use `.feature-editor-value` here because the dropdowns are placed higher in the DOM to +// be able to overlap with other content +.k-item,.k-list-item { + .item-title { + font-weight: bolder; + } + + .item-title .badge { + font-size: 8px; + } + + .item-rank { + font-weight: lighter; + } + + .item-identifier { + font-size: 85%; + line-height: normal; + font-style: italic; + padding-left: 10px; + } + + .item-description { + font-size: 85%; + font-weight: lighter; + white-space: normal; + line-height: normal; + padding-left: 10px; + } } diff --git a/inception/inception-bootstrap/src/main/ts/bootstrap/shim-kendo.scss b/inception/inception-bootstrap/src/main/ts/bootstrap/shim-kendo.scss index 93c9f7bc667..dcb7b5f345d 100644 --- a/inception/inception-bootstrap/src/main/ts/bootstrap/shim-kendo.scss +++ b/inception/inception-bootstrap/src/main/ts/bootstrap/shim-kendo.scss @@ -91,13 +91,35 @@ background-color: var(--bs-light); } -.k-input:disabled { - background-color: #e9ecef; - opacity: 1; - padding: 6px 12px; +.k-input { + &:disabled { + background-color: #e9ecef; + opacity: 1; + padding: 6px 12px; + } + + &.form-control { + // Bootstrap form-control overrides the Kendo style, so we need to restore it + display: inline-flex !important; + } +} + + +.k-input-inner { + &.k-input:focus { + // Remove double focus shadow in composite components like combo boxes + box-shadow: none; + } + + &.form-control { + // Bootstrap form-control overrides the Kendo style, so we need to restore it + display: inline-flex !important; + padding: 0px; + } } -// Remove double focus shadow in composite components like combo boxes -.k-input-inner.k-input:focus { - box-shadow: none; +.k-list-container > .k-footer { + background-color: #eeeeee; + border-top: 1px solid #bbb; + padding: 3px 10px; } diff --git a/inception/inception-support/src/main/java/de/tudarmstadt/ukp/clarin/webanno/support/StyledComboBox.java b/inception/inception-support/src/main/java/de/tudarmstadt/ukp/clarin/webanno/support/StyledComboBox.java index 41eb57838ef..0508c504853 100644 --- a/inception/inception-support/src/main/java/de/tudarmstadt/ukp/clarin/webanno/support/StyledComboBox.java +++ b/inception/inception-support/src/main/java/de/tudarmstadt/ukp/clarin/webanno/support/StyledComboBox.java @@ -86,10 +86,11 @@ public String getText() // Some docs on how the templates work in Kendo, in case we need // more fancy dropdowns // http://docs.telerik.com/kendo-ui/framework/templates/overview - return "# if (data.reordered == 'true') { #" - + "
#: data.name #
\n" - + "# } else { #" - + "
#: data.name #
\n" + "# } #"; + return "# if (data.reordered == 'true') { #" // + + "#: data.name #\n" // + + "# } else { #" // + + "#: data.name #\n" // + + "# } #"; } @Override diff --git a/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/kendo/KendoStyleUtils.java b/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/kendo/KendoStyleUtils.java new file mode 100644 index 00000000000..4bab93fa5e0 --- /dev/null +++ b/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/kendo/KendoStyleUtils.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Technische Universität Darmstadt under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The Technische Universität Darmstadt + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. + * + * 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 de.tudarmstadt.ukp.inception.support.kendo; + +import static java.lang.String.join; + +import com.googlecode.wicket.jquery.core.JQueryBehavior; + +public class KendoStyleUtils +{ + /** + * Use one-third of the browser width but not less than 300 pixels. This is better than using + * the Kendo auto-sizing feature because that sometimes doesn't get the width right. + * + * @param aBehavior + * behavior associated with the component having the dropdown. + */ + public static void autoDropdownWidth(JQueryBehavior aBehavior) + { + aBehavior.setOption("open", join(" ", // + "function(e) {", // + " var listContainer = e.sender.list.closest('.k-popup');", // + " listContainer.width(Math.max($(window).width()*0.3+kendo.support.scrollbar(),300))", // + "}")); + } + + /** + * Use one-third of the browser height but not less than 200 pixels. This is better than using + * the Kendo auto-sizing feature because that sometimes doesn't get the height right. + * + * @param aBehavior + * behavior associated with the component having the dropdown. + */ + public static void autoDropdownHeight(JQueryBehavior aBehavior) + { + // + aBehavior.setOption("height", "Math.max($(window).height()*0.5,200)"); + } + + /** + * Prevent scrolling action from closing the dropdown while the focus is on the input field. The + * solution we use here is a NASTY hack, but I didn't find any other way to cancel out only the + * closing triggered by scrolling the browser window without having other adverse side effects + * such as mouse clicks or enter no longer selecting and closing the dropdown. See: + * https://github.com/inception-project/inception/issues/1517 + * + * @param aBehavior + * behavior associated with the component having the dropdown. + */ + public static void keepDropdownVisibleWhenScrolling(JQueryBehavior aBehavior) + { + // aBehavior.setOption("close", join(" ", // + // "function(e) {", // + // " if (document.activeElement == e.sender.element[0]) {", // + // " e.preventDefault();", // + // " }", // + // "}")); + + aBehavior.setOption("close", join(" ", // + "function(e) {", // + " if (new Error().stack.toString().includes('_resize')) {", // + " e.preventDefault();", // + " }", // + "}")); + } + + /** + * Reset the values in the dropdown listbox to avoid that when opening the dropdown the next + * time ALL items with the same label as the selected item appear as selected + * + * @param aBehavior + * behavior associated with the component having the dropdown. + */ + public static void resetDropdownSelectionOnOpen(JQueryBehavior aBehavior) + { + aBehavior.setOption("filtering", join(" ", // + "function(e) {", // + " e.sender.listView.value([]);", // + "}")); + } +} diff --git a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor.html b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor.html index f9a8ebf1f9f..61565d7855b 100644 --- a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor.html +++ b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureEditor.html @@ -33,7 +33,7 @@ - +
diff --git a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/KBHandleTemplate.java b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/KBHandleTemplate.java index 599ea46c7eb..256bd162b5a 100644 --- a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/KBHandleTemplate.java +++ b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/KBHandleTemplate.java @@ -35,29 +35,25 @@ final class KBHandleTemplate public String getText() { StringBuilder sb = new StringBuilder(); - sb.append("
"); - sb.append("
"); + sb.append(""); // We cannot use && here because that causes an XML parse error in the browser - so we nest // the if clauses... sb.append(" # if (data.rank) { if (data.rank != '0') { #"); - sb.append(" "); - sb.append(" [${ data.rank }]"); - sb.append(" "); + sb.append(" [${ data.rank }]"); sb.append(" # } } #"); - sb.append(" ${ data.uiLabel }"); - sb.append("
"); - sb.append("
"); - sb.append(" ${ data.identifier }"); - sb.append("
"); - sb.append("
"); - sb.append(" ${ data.description }"); - sb.append("
"); + sb.append(" ${ data.uiLabel }"); + sb.append(""); + sb.append("
"); + sb.append(" ${ data.identifier }"); + sb.append("
"); + sb.append("
"); + sb.append(" ${ data.description }"); + sb.append("
"); if (DEVELOPMENT.equals(Application.get().getConfigurationType())) { - sb.append("
"); - sb.append(" ${ data.debugInfo }"); - sb.append("
"); + sb.append("
"); + sb.append(" ${ data.debugInfo }"); + sb.append("
"); } - sb.append("
"); return sb.toString(); } diff --git a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/KnowledgeBaseItemAutoCompleteField.java b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/KnowledgeBaseItemAutoCompleteField.java index e02fe92d840..cc525a8c2a1 100644 --- a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/KnowledgeBaseItemAutoCompleteField.java +++ b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/KnowledgeBaseItemAutoCompleteField.java @@ -31,6 +31,7 @@ import com.googlecode.wicket.kendo.ui.form.autocomplete.AutoCompleteTextField; import de.tudarmstadt.ukp.inception.kb.graph.KBHandle; +import de.tudarmstadt.ukp.inception.support.kendo.KendoStyleUtils; /** * Auto-complete field for accessing a knowledge base. @@ -77,36 +78,20 @@ protected List getChoices(String aInput) } @Override - public void onConfigure(JQueryBehavior behavior) + public void onConfigure(JQueryBehavior aBehavior) { - super.onConfigure(behavior); + super.onConfigure(aBehavior); - behavior.setOption("ignoreCase", false); - behavior.setOption("delay", 500); - behavior.setOption("animation", false); - behavior.setOption("footerTemplate", + aBehavior.setOption("ignoreCase", false); + aBehavior.setOption("delay", 500); + aBehavior.setOption("animation", false); + aBehavior.setOption("footerTemplate", Options.asString("#: instance.dataSource.total() # items found")); - // Use one-third of the browser width but not less than 300 pixels. This is better than - // using the Kendo auto-sizing feature because that sometimes doesn't get the width right. - behavior.setOption("height", "Math.max($(window).height()*0.5,200)"); - behavior.setOption("open", String.join(" ", "function(e) {", - " e.sender.list.width(Math.max($(window).width()*0.3,300));", "}")); - - // Reset the values in the dropdown listbox to avoid that when opening the dropdown the next - // time ALL items with the same label as the selected item appear as selected - behavior.setOption("filtering", - String.join(" ", "function(e) {", " e.sender.listView.value([]);", "}")); - - // Prevent scrolling action from closing the dropdown while the focus is on the input field - // The solution we use here is a NASTY hack, but I didn't find any other way to cancel out - // only the closing triggered by scrolling the browser window without having other adverse - // side effects such as mouse clicks or enter no longer selecting and closing the dropdown. - // See: https://github.com/inception-project/inception/issues/1517 - behavior.setOption("close", - String.join(" ", "function(e) {", - " if (new Error().stack.toString().includes('_resize')) {", - " e.preventDefault();", " }", "}")); + KendoStyleUtils.autoDropdownHeight(aBehavior); + KendoStyleUtils.autoDropdownWidth(aBehavior); + KendoStyleUtils.resetDropdownSelectionOnOpen(aBehavior); + KendoStyleUtils.keepDropdownVisibleWhenScrolling(aBehavior); } @Override