# ExamplesS

## About

As system evolves and gets a lot of changes, this section contains referencing code examples. Snippets below gets extracted from an actual project code, so these are always reliable. Use IDE, if needed, in order to search for specific classes or files.

## Documentation

Recommended approaches and samples may be always found here.

DrawIO diagrams:

- Custom Plugin

- Document Processing

- GIT Workflow

Other samples:

- Ditaa Diagram

- Configuration from links from it

- Complex table and includes

## Code

### Saving latest/last user request parameters

Let’s take interface filters, as example - use restoreRequestParams method in org.bgerp.action.base.BaseAction

Saving and restoring a value at once:

    // PzdcDoc snippet of: 'ru.bgcrm.struts.action.ProcessLinkAction', lines: 51 - 52

    public ActionForward linkedProcessList(DynActionForm form, ConnectionSet conSet) throws Exception {
        restoreRequestParams(conSet.getConnection(), form, true, true, "open");

### Feature flag for UI

Option stored in user personalization map. UI dropbox available in user profile settings.

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/profile/default.jsp', lines: 49 - 55 --%>

    <c:set var="key" value="iface.process.card.extend.right.on.scroll.down"/>
    <ui:combo-single name="${key}" value="${ctxUser.pers.get(key, '1')}" widthTextValue="15em">
            <jsp:attribute name="valuesHtml">
                    <li value="1">${l.l('Yes')}</li>
                    <li value="0">${l.l('No')}</li>
            </jsp:attribute>
    </ui:combo-single>

Stored values may be read in JSP pages using in the same ctxUser.pers way, but also available in JS via $$.pers:

    // PzdcDoc snippet of: 'webapps/js/kernel.shell.js', lines: 458 - 459

    if (($$.pers["iface.buffer.openOnLongPress"] || 0) === 1) {
            const debug = $$.debug("buffer");

### Depicting element count on a tab

For example, showing associated processes count. Gets saved on the first call. Use ru.bgcrm.model.IfaceState class.

Show on a tab’s header:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/process/process/process_editor.jsp', lines: 77 - 88 --%>

            <c:if test="${processType.properties.configMap.getSok('1', false, 'show.tab.links.process', 'processShowProcessLinks') eq '1'}">
                    <c:set var="ifaceId" value="link_process"/>
                    <c:set var="ifaceState" value="${ifaceStateMap[ifaceId]}"/>

                    <c:url var="url" value="/user/process/link/process.do">
                            <c:param name="id" value="${process.id}"/>
                            <c:param name="ifaceId" value="${ifaceId}"/>
                            <c:param name="ifaceState" value="${ifaceState.state}"/>
                    </c:url>

                    $tabs.tabs("add", "${url}", "${l.l('Related Processes')}<span class='iface-state'>${ifaceState.formattedState}</span>");
            </c:if>

Update value in DB:

    // PzdcDoc snippet of: 'org.bgerp.action.ProcessLinkProcessAction', lines: 59 - 67

    IfaceState currentState = new IfaceState(form);
    if (Utils.notBlankString(currentState.getIfaceId())) {
        Pair<Integer, Integer> counts = new ProcessLinkDAO(conSet.getSlaveConnection()).getLinkedProcessesCounts(form.getId());

        IfaceState newState = new IfaceState(Process.OBJECT_TYPE, form.getId(), form,
                String.valueOf(counts.getFirst()),
                String.valueOf(counts.getSecond()));
        new IfaceStateDAO(conSet.getConnection()).compareAndUpdateState(currentState, newState, form);
    }

Refresh on a tab’s header:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/process/process/link/process/default.jsp', lines: 6 - 10 --%>

    <script>
            $(function () {
                    $$.ui.ifaceStateTabUpdate('${uiid}', '${ifaceState.formattedState}');
            })
    </script>

### Date and time format

When formatting date and time values in Java or JSP , use the following formats in order to keep unified approach and maintain independence from the current locale:

- ymd - year, month, date;

- ymdh - year, month, day, hour;

- ymdhm - year, month, day, hour, minute;

- ymdhms - year, month, day, hour, minute, second.

Java code uses ru.bgcrm.util.TimeUtils class for date formatting, this class also contains format constants.

The same functions may be used in JSP using `tu` prefix:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/parameter/edit.jsp', lines: 149 - 149 --%>

    <input type="text" name="value" value="${tu.format(frd.value, type)}" id="${focusFieldUiid}" ${changeAttrs}/>

### Configuration Java Beans

In order to speed up parsing and validation, use Java class objects inherited from org.bgerp.app.cfg.Config For example: org.bgerp.model.process.config.IsolationConfig. This configuration supports constructor with a validation flag, which allows to check syntax when saving.

Configuration bin can be also obtained in JSP:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/message/process/edit/tags.jsp', lines: 6 - 6 --%>

    <c:set var="tagConfig" value="${ctxSetup.getConfig('org.bgerp.model.msg.config.TagConfig')}"/>

However, try to avoid doing it, as it depends on Java package and can be broken during refactoring. If the configuration cannot be retrieved in Java action, use at least a bean name:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/message/process/edit/editor.jsp', lines: 7 - 7 --%>

    <c:set var="config" value="${ctxSetup.getConfig('MessageTypeConfig')}"/>

### Pagination

Putting results into JSP and rendering a form:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/process/status/list.jsp', lines: 4 - 18 --%>

    <html:form action="${form.requestURI}" styleClass="in-mr1">
            <input type="hidden" name="method" value="statusList"/>
            <input type="hidden" name="id" value="-1"/>
            <input type="hidden" name="returnUrl" value="${form.requestUrl}"/>

            <c:url var="url" value="${form.requestURI}">
                    <c:param name="method" value="statusGet"/>
                    <c:param name="id" value="-1"/>
                    <c:param name="returnUrl" value="${form.requestUrl}"/>
            </c:url>

            <ui:button type="add" onclick="$$.ajax.loadContent('${url}', this)"/>

            <ui:page-control/>
    </html:form>

Java action:

    // PzdcDoc snippet of: 'ru.bgcrm.struts.action.admin.ProcessAction', lines: 52 - 56

        public ActionForward statusList(DynActionForm form, Connection con) throws Exception {
            new StatusDAO(con).searchStatus(new Pageable<>(form));

            return html(con, form, PATH_JSP + "/status/list.jsp");
        }

### File upload

JSP page:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/license/license.jsp', lines: 9 - 16 --%>

            <form action="${form.requestURI}" method="POST" enctype="multipart/form-data">
                    <input type="hidden" name="method" value="upload"/>
                    <input type="hidden" name="responseType" value="json"/>
                    <input type="file" name="file" style="visibility: hidden; display: none;"/>
                    <button type="button" class="btn-grey w100p mt1" onclick="$$.ajax.fileUpload(this.form).done(() => {
                            $$.ajax.loadContent('${form.requestUrl}', this);
                    })">${l.l('Загрузить файл лицензии')}</button>
            </form>

Put an attention to the ${form.requestURI} expression, which gets action URL of the current action and prevents duplication of code.

Action:

    // PzdcDoc snippet of: 'org.bgerp.action.admin.LicenseAction', lines: 29 - 42

    public ActionForward upload(DynActionForm form, ConnectionSet conSet) throws Exception {
        var file = form.getFile();

        byte[] data = IOUtils.toByteArray(file.getInputStream());

        String error = new License(new String(data, StandardCharsets.UTF_8)).getError();
        if (Utils.notBlankString(error))
            throw new BGMessageException(error);

        IOUtils.write(data, new FileOutputStream(License.FILE_NAME));
        AppLicense.init();

        return json(conSet, form);
    }

### UI: JSP, HTML/CSS, JS

#### AJAX

A simple dictionary with pagination, AJAX editor invocation: webapps/WEB-INF/jspf/admin/process/status/list.jsp

Using AJAX for updating or restoring data and cancel editing in process type properties editor:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/process/type/properties.jsp', lines: 153 - 160 --%>

            <div class="mt1">
                    <ui:form-ok-cancel/>
                    <span style="float: right;">
                            <button type="button" class="btn-grey mr1" onclick="${saveCommand}"
                                    title="${l.l('Save without leaving editor')}">${l.l('Save')}</button>
                            <button type="button" class="btn-grey" onclick="$$.ajax.load('${editUrl}', $('#${formUiid}').parent())">${l.l('Restore')}</button>
                    </span>
            </div>

##### AJAX Progress Button Indication

Sending AJAX request and showing progress indicator on button during execution:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/run/run.jsp', lines: 20 - 24 --%>

                    <button class="btn-grey ml1 icon" type="button" onclick="
                            $$.ajax.post(this)
                                    .done(() => {
                                            alert(this.form.sync.value ? '${l.l('Класс выполнен, проверьте логи')}' : '${l.l('Класс запущен в отдельном потоке,\\nвывод в логах.')}')
                                    })"><i class="ti-control-play"></i></button>

The same but for $$.ajax.load function:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/process/queue/filter.jsp', lines: 602 - 602 --%>

    <ui:button type="out" styleClass="out" onclick="const $form = $('${selectorForm}'); processQueueMarkFilledFilters($form); $$.ajax.load($form, $('#processQueueData'), {control: this});"/>

#### Java Constants in JSP

Flex layout, using constants from Java classes (defined in process_search_constants.jsp), print button close to a field:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/search/search.jsp', lines: 68 - 82 --%>

    <div style="display: flex;">
            <u:sc>
                    <%@ include file="process_search_constants.jsp"%>
                    <ui:combo-single name="mode" styleClass="w100p">
                            <jsp:attribute name="valuesHtml">
                                    <li value="${MODE_USER_CREATED}">${l.l('Cозданные мной')}</li>
                                    <li value="${MODE_USER_CLOSED}">${l.l('Закрытые мной')}</li>
                                    <li value="${MODE_USER_STATUS_CHANGED}">${l.l('Статус изменён мной')}</li>
                            </jsp:attribute>
                    </ui:combo-single>
            </u:sc>
            <div class="pl05">
                    <ui:button type="out" onclick="this.form.searchBy.value='userId'; $$.ajax.load(this.form, '#searchResult');"/>
            </div>
    </div>

| For some reason a class, containing included constant, must not contain `config` word in package path.

#### Refresh on Show

Snap-in refresh upon moving back to it, onShow:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/log/log.jsp', lines: 17 - 24 --%>

    <script>
            $(function () {
                    const $content = $('#${uiid}').parent();
                    $content.data('onShow', function () {
                            $$.ajax.load("${form.requestUrl}", $content);
                    });
            });
    </script>

#### Restore Form Parameter Values

Restore form parameter values:

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/directory/parameter/group/update.jsp', lines: 8 - 10 --%>

    <html:form action="/admin/directory" styleClass="center500">
            <input type="hidden" name="method" value="parameterGroupUpdate"/>
            <html:hidden property="directoryId"/>

#### Toggle Button

    <%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/process/message_possible_process_list.jsp', lines: 15 - 17 --%>

    <button type="button"
                    onclick="this.form.open.value = this.form.open.value ? '' : 'true'; ${sendCommand}"
                    class="mr1 btn-small ${form.param.open eq 'true' ? 'btn-blue' : 'btn-white'}">${l.l('Open only')}</button>