• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanodash / 29007665799

09 Jul 2026 09:17AM UTC coverage: 28.481% (+0.1%) from 28.362%
29007665799

push

github

web-flow
Merge pull request #550 from knowledgepixels/fix/optional-introduced-fillable-on-supersede

fix: keep optional introduced placeholders fillable on supersede

1867 of 7365 branches covered (25.35%)

Branch coverage included in aggregate %.

3770 of 12427 relevant lines covered (30.34%)

4.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.78
src/main/java/com/knowledgepixels/nanodash/component/ValueItem.java
1
package com.knowledgepixels.nanodash.component;
2

3
import com.knowledgepixels.nanodash.component.PublishForm.FillMode;
4
import com.knowledgepixels.nanodash.component.StatementItem.RepetitionGroup;
5
import com.knowledgepixels.nanodash.template.Template;
6
import com.knowledgepixels.nanodash.template.UnificationException;
7
import org.apache.wicket.Component;
8
import org.apache.wicket.ajax.AjaxRequestTarget;
9
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
10
import org.eclipse.rdf4j.model.IRI;
11
import org.eclipse.rdf4j.model.Literal;
12
import org.eclipse.rdf4j.model.Statement;
13
import org.eclipse.rdf4j.model.Value;
14
import org.eclipse.rdf4j.model.vocabulary.XSD;
15
import org.nanopub.Nanopub;
16
import org.nanopub.vocabulary.NPX;
17
import org.nanopub.vocabulary.NTEMPLATE;
18

19
/**
20
 * ValueItem is a panel that represents a single value in a statement.
21
 */
22
public class ValueItem extends AbstractContextComponent {
23

24
    private ContextComponent component;
25
    private Value value;
26

27
    /**
28
     * Constructor for ValueItem.
29
     *
30
     * @param id              the component id
31
     * @param value           the value to be represented
32
     * @param statementPartId the IRI of the statement part this value belongs to
33
     * @param rg              the repetition group this value is part of
34
     */
35
    public ValueItem(String id, Value value, IRI statementPartId, RepetitionGroup rg) {
36
        super(id, rg.getContext());
15✔
37
        this.value = value;
9✔
38
        final Template template = this.context.getTemplate();
12✔
39
        if (value instanceof IRI) {
9✔
40
            IRI iri = (IRI) value;
9✔
41
            if (template.isSequenceElementPlaceholder(iri)) {
12!
42
                component = new SequenceElementItem("value", iri, rg.getRepeatIndex() + 1, this.context);
×
43
            } else if (iri.equals(NTEMPLATE.CREATOR_PLACEHOLDER) || template.isRootNanopubPlaceholder(iri)) {
24!
44
                // These are special placeholders that are always read-only
45
                component = new ReadonlyItem("value", id, iri, statementPartId, rg);
33✔
46
            } else if (this.context.isReadOnly()) {
12✔
47
                if (template.isPlaceholder(iri) || template.isIntroducedResource(iri) || template.isEmbeddedResource(iri)) {
36!
48
                    component = new ReadonlyItem("value", id, iri, statementPartId, rg);
33✔
49
                } else {
50
                    component = new IriItem("value", id, iri, id.equals("obj"), statementPartId, rg);
42✔
51
                }
52
            } else if (template.isRestrictedChoicePlaceholder(iri)) {
12✔
53
                component = new RestrictedChoiceItem("value", id, iri, rg.isOptional(), this.context);
39✔
54
            } else if (template.isAgentPlaceholder(iri)) {
12✔
55
                component = new AgentChoiceItem("value", id, iri, rg.isOptional(), this.context);
39✔
56
            } else if (template.isGuidedChoicePlaceholder(iri)) {
12✔
57
                component = new GuidedChoiceItem("value", id, iri, rg.isOptional(), this.context);
39✔
58
            } else if (template.isIntroducedResource(iri) && (this.context.getFillMode() == FillMode.SUPERSEDE || this.context.getFillMode() == FillMode.OVERRIDE)
48!
59
                    && introducesAnything(this.context.getFillSource())) {
9✔
60
                // An introduced resource keeps its IRI across versions, so it is pinned
61
                // read-only on supersede/override -- but only if the source nanopub
62
                // actually introduces something to pin. Otherwise (e.g. an optional
63
                // statement whose introduced identifier the old version didn't declare
64
                // yet) the field must stay fillable (issue #549).
65
                component = new ReadonlyItem("value", id, iri, statementPartId, rg);
33✔
66
            } else if (template.isUriPlaceholder(iri)) {
12✔
67
                component = new IriTextfieldItem("value", id, iri, rg.isOptional(), this.context);
39✔
68
            } else if (template.isLongLiteralPlaceholder(iri)) {
12✔
69
                component = new LiteralTextareaItem("value", iri, rg.isOptional(), this.context);
36✔
70
            } else if (template.isLiteralPlaceholder(iri)) {
12✔
71
                // TODO add all date time types
72
                if (XSD.DATE.equals(template.getDatatype(iri))) {
18!
73
                    component = new LiteralDateItem("value", iri, rg.isOptional(), this.context);
×
74
                } else if (XSD.DATETIME.equals(template.getDatatype(iri))) {
18!
75
                    component = new LiteralDateTimeItem("value", iri, rg.isOptional(), this.context);
×
76
                } else {
77
                    component = new LiteralTextfieldItem("value", iri, rg.isOptional(), this.context);
36✔
78
                }
79
            } else if (template.isPlaceholder(iri)) {
12!
80
                component = new ValueTextfieldItem("value", id, iri, rg.isOptional(), this.context);
×
81
            } else {
82
                component = new IriItem("value", id, iri, id.equals("obj"), statementPartId, rg);
39✔
83
            }
84
        } else {
3✔
85
            component = new LiteralItem("value", id, (Literal) value, rg);
30✔
86
        }
87
        add((Component) component);
33✔
88
    }
3✔
89

90
    private static boolean introducesAnything(Nanopub np) {
91
        if (np == null) return false;
12✔
92
        for (Statement st : np.getPubinfo()) {
33✔
93
            if (st.getSubject().equals(np.getUri()) && st.getPredicate().equals(NPX.INTRODUCES) && st.getObject() instanceof IRI) {
45!
94
                return true;
6✔
95
            }
96
        }
3✔
97
        return false;
6✔
98
    }
99

100
    /**
101
     * OnChangeAjaxBehavior that keeps the value after a refresh.
102
     */
103
    public static class KeepValueAfterRefreshBehavior extends OnChangeAjaxBehavior {
9✔
104

105
        @Override
106
        protected void onUpdate(AjaxRequestTarget target) {
107
            // No actual action needed here; Ajax request alone ensures values are kept after refreshing.
108
        }
×
109

110
    }
111

112
    /**
113
     * {@inheritDoc}
114
     */
115
    @Override
116
    public void removeFromContext() {
117
        component.removeFromContext();
9✔
118
    }
3✔
119

120
    /**
121
     * {@inheritDoc}
122
     */
123
    @Override
124
    public boolean isUnifiableWith(Value v) {
125
        return component.isUnifiableWith(v);
15✔
126
    }
127

128
    /**
129
     * {@inheritDoc}
130
     */
131
    @Override
132
    public void unifyWith(Value v) throws UnificationException {
133
        component.unifyWith(v);
12✔
134
    }
3✔
135

136
    /**
137
     * {@inheritDoc}
138
     */
139
    @Override
140
    public void fillFinished() {
141
        component.fillFinished();
9✔
142
    }
3✔
143

144
    /**
145
     * {@inheritDoc}
146
     */
147
    @Override
148
    public void finalizeValues() {
149
        component.finalizeValues();
9✔
150
    }
3✔
151

152
    /**
153
     * Get the value represented by this ValueItem.
154
     *
155
     * @return the value
156
     */
157
    public Value getValue() {
158
        return value;
×
159
    }
160

161
    /**
162
     * Get the component that represents this ValueItem.
163
     *
164
     * @return the ContextComponent that represents this ValueItem
165
     */
166
    public ContextComponent getComponent() {
167
        return component;
×
168
    }
169

170
    /**
171
     * <p>toString.</p>
172
     *
173
     * @return a {@link java.lang.String} object
174
     */
175
    public String toString() {
176
        return component.toString();
×
177
    }
178

179
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc