src/main/resources/lib/custom/customRepeatable.jelly
<!--
~ MIT License
~
~ Copyright 2012-2024 Open Text
~
~ The only warranties for products and services of Open Text and
~ its affiliates and licensors ("Open Text") are as may be set forth
~ in the express warranty statements accompanying such products and services.
~ Nothing herein should be construed as constituting an additional warranty.
~ Open Text shall not be liable for technical or editorial errors or
~ omissions contained herein. The information contained herein is subject
~ to change without notice.
~
~ Except as specifically indicated otherwise, this document contains
~ confidential information and a valid license is required for possession,
~ use or copying. If this work is provided to the U.S. Government,
~ consistent with FAR 12.211 and 12.212, Commercial Computer Software,
~ Computer Software Documentation, and Technical Data for Commercial Items are
~ licensed to the U.S. Government under vendor's standard commercial license.
~
~ 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.
~ ___________________________________________________________________
-->
<!--
tamasflorin: An easier way to provide dynamic id to the entry titles for each repeatable item.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<st:adjunct includes="lib.form.repeatable.repeatable"/>
<script>
// handle a single button
function handleOne(button,loading) {
// jelly represents each item as a div with class "tr" with data inside
var parent = button.closest('.tr');
if (!parent) return false;
// the containers will also contain the setting name
var repeatableContainer = parent.getElementsByClassName('repeated-container')[0];
if (!repeatableContainer) return false;
// find all the settings that have our custom class
// as we do not want to change the normal behaviour
var settings = repeatableContainer.getElementsByClassName("environment-title");
// add an integer number to each custom setting item
for (var i = 0; i < settings.length; i++) {
settings[i].innerHTML = settings[i].title + (loading ? i : i + 1);
}
}
// handle all the custom repeatable's on the current page
function setNames(loading) {
var buttons = document.getElementsByName('customRepeatableButton');
for(var i = 0; i < buttons.length; i++) {
handleOne(buttons[i],loading);
}
}
document.addEventListener('DOMContentLoaded', function() {
setNames(true);
}, false);
</script>
<!--
If bi-directional binding, fill in the rest of attributes automatically
-->
<j:choose>
<j:when test="${attrs.field!=null}">
<j:set var="name" value="${field}"/>
<j:set var="var" value="instance"/>
<j:set var="items" value="${instance[name] ?: attrs.default}"/>
<j:set var="buttonName" value="${attrs.addCount ? 'customRepeatableButton' : 'simpleRepeatableButton'}"/>
<!-- and expose update descriptor to the body of this tag -->
<j:set var="descriptor" value="${descriptor.getPropertyType(instance,field).itemTypeDescriptorOrDie}" />
</j:when>
<j:otherwise>
<j:set var="name" value="${attrs.name?:attrs.var}"/>
<j:set var="items" value="${attrs.items ?: attrs.default}"/>
</j:otherwise>
</j:choose>
<div class="repeated-container${!empty(header)?' with-drag-drop':''}" style="border-left: none;">
<!-- The first DIV is the master copy. -->
<div class="repeated-chunk to-be-removed" name="${name}">
<j:if test="${!empty(header)}"><div class="dd-handle">${header}</div></j:if>
<j:scope>
<j:set var="${var}" value="${null}"/>
<d:invokeBody />
</j:scope>
</div>
<!-- then populate them for each item -->
<j:forEach var="loop" varStatus="loopStatus" items="${items}">
<div class="repeated-chunk" name="${name}">
<j:set var="${var}" value="${loop}" />
<j:if test="${!empty(header)}"><div class="dd-handle">${header}</div></j:if>
<d:invokeBody />
</div>
</j:forEach>
<j:remove var="${var}" />
<j:if test="${minimum > 0}">
<j:forEach begin="${h.size2(items)}" end="${minimum-1}" var="i">
<j:set var="${var}" value="${null}" />
<div class="repeated-chunk" name="${name}">
<j:if test="${!empty(header)}"><div class="dd-handle">${header}</div></j:if>
<d:invokeBody />
</div>
</j:forEach>
</j:if>
<div class="repeatable-insertion-point" />
<j:if test="${!attrs.noAddButton}">
<!--<div style="display:flex;flex-direction: row;margin-left: 24px;">-->
<j:choose>
<j:when test="${buttonName.equals('customRepeatableButton')}">
<input type="button" value="${attrs.add?:'%Add'}" class="repeatable-add"
onClick="setNames(false)" name="${buttonName}"
style="color:black; background-color: rgb(229,241,252);"/>
</j:when>
<j:otherwise>
<input type="button" value="${attrs.add?:'%Add'}" class="repeatable-add"
onClick="setNames(false)" name="${buttonName}"/>
</j:otherwise>
</j:choose>
<!--</div>-->
</j:if>
</div>
</j:jelly>