Package com.psddev.cms.tool

Source Code of com.psddev.cms.tool.SearchResultRenderer

package com.psddev.cms.tool;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import com.psddev.dari.db.PredicateParser;
import org.joda.time.DateTime;

import com.psddev.cms.db.Directory;
import com.psddev.cms.db.Renderer;
import com.psddev.cms.db.Site;
import com.psddev.cms.db.Taxon;
import com.psddev.cms.db.ToolUi;
import com.psddev.dari.db.Database;
import com.psddev.dari.db.Metric;
import com.psddev.dari.db.MetricInterval;
import com.psddev.dari.db.ObjectField;
import com.psddev.dari.db.ObjectType;
import com.psddev.dari.db.Predicate;
import com.psddev.dari.db.Query;
import com.psddev.dari.db.Recordable;
import com.psddev.dari.db.State;
import com.psddev.dari.util.ObjectUtils;
import com.psddev.dari.util.PaginatedResult;
import com.psddev.dari.util.StorageItem;
import com.psddev.dari.util.StringUtils;

public class SearchResultRenderer {

    public static final String TAXON_LEVEL_PARAMETER = "taxonLevel";

    private static final String ATTRIBUTE_PREFIX = SearchResultRenderer.class.getName() + ".";
    private static final String PREVIOUS_DATE_ATTRIBUTE = ATTRIBUTE_PREFIX + "previousDate";
    private static final String MAX_SUM_ATTRIBUTE = ATTRIBUTE_PREFIX + ".maximumSum";
    private static final String TAXON_PARENT_ID_PARAMETER = "taxonParentId";
    private static final String SORT_SETTING_PREFIX = "sort/";

    protected final ToolPageContext page;

    @Deprecated
    protected final PageWriter writer;

    protected final Search search;
    protected final ObjectField sortField;
    protected final boolean showSiteLabel;
    protected final boolean showTypeLabel;
    protected final PaginatedResult<?> result;

    @SuppressWarnings("deprecation")
    public SearchResultRenderer(ToolPageContext page, Search search) throws IOException {
        this.page = page;
        this.writer = page.getWriter();
        this.search = search;

        ObjectType selectedType = search.getSelectedType();
        ToolUi ui = selectedType == null ? null : selectedType.as(ToolUi.class);
        PaginatedResult<?> result = null;

        if (selectedType != null) {
            if (search.getSort() != null) {
                AuthenticationFilter.Static.putUserSetting(page.getRequest(), SORT_SETTING_PREFIX + selectedType.getId(), search.getSort());

            } else {
                Object sortSetting = AuthenticationFilter.Static.getUserSetting(page.getRequest(), SORT_SETTING_PREFIX + selectedType.getId());

                if (!ObjectUtils.isBlank(sortSetting)) {
                    search.setSort(sortSetting.toString());
                }
            }
        }

        if (search.getSort() == null) {
            search.setShowMissing(true);

            if (ui != null && ui.getDefaultSortField() != null) {
                search.setSort(ui.getDefaultSortField());

            } else if (!ObjectUtils.isBlank(search.getQueryString())) {
                search.setSort(Search.RELEVANT_SORT_VALUE);

            } else {
                Map<String, String> f = search.getFieldFilters().get("cms.content.publishDate");

                if (f != null &&
                        (f.get("") != null ||
                        f.get("x") != null)) {
                    search.setSort("cms.content.publishDate");

                } else {
                    search.setSort("cms.content.updateDate");
                }
            }
        }

        showSiteLabel = Query.from(CmsTool.class).first().isDisplaySiteInSearchResult() &&
                page.getSite() == null &&
                Query.from(Site.class).hasMoreThan(0);

        if (selectedType != null) {
            this.sortField = selectedType.getFieldGlobally(search.getSort());
            this.showTypeLabel = selectedType.as(ToolUi.class).findDisplayTypes().size() != 1;

            if (ObjectType.getInstance(ObjectType.class).equals(selectedType)) {
                List<ObjectType> types = new ArrayList<ObjectType>();
                Predicate predicate = search.toQuery(page.getSite()).getPredicate();

                for (ObjectType t : Database.Static.getDefault().getEnvironment().getTypes()) {
                    if (t.is(predicate)) {
                        types.add(t);
                    }
                }

                result = new PaginatedResult<ObjectType>(search.getOffset(), search.getLimit(), types);
            }

        } else {
            this.sortField = Database.Static.getDefault().getEnvironment().getField(search.getSort());
            this.showTypeLabel = search.findValidTypes().size() != 1;
        }

        this.result = result != null ? result : search.toQuery(page.getSite()).select(search.getOffset(), search.getLimit());
    }

    @SuppressWarnings("unchecked")
    public void render() throws IOException {
        boolean resultsDisplayed = false;
        int level = page.paramOrDefault(int.class, TAXON_LEVEL_PARAMETER, 1);

        if (level == 1) {
            page.writeStart("h2").writeHtml("Result").writeEnd();
        }

        // check if the Taxon UI should be displayed
        ObjectType taxonType = null;
        if (ObjectUtils.isBlank(search.getQueryString()) &&
                search.getVisibilities().isEmpty()) {

            if (search.getSelectedType() != null) {

                if (search.getSelectedType().getGroups().contains(Taxon.class.getName())) {
                    taxonType = search.getSelectedType();
                }

            } else if (search.getTypes() != null && search.getTypes().size() == 1) {

                ObjectType searchType = search.getTypes().iterator().next();

                if (searchType.getGroups().contains(Taxon.class.getName())) {
                    taxonType = searchType;
                }
            }
        }

        // display the taxon UI if the type is not null
        if (taxonType != null) {

            search.setSuggestions(false);

            int nextLevel = level + 1;
            Collection<Taxon> taxonResults = null;
            UUID taxonParentUuid = page.paramOrDefault(UUID.class, TAXON_PARENT_ID_PARAMETER, null);
            Site site = page.getSite();
            Predicate predicate = search.toQuery(page.getSite()).getPredicate();

            if (!ObjectUtils.isBlank(taxonParentUuid)) {

                Taxon parent = Query.findById(Taxon.class, taxonParentUuid);
                taxonResults = (Collection<Taxon>) Taxon.Static.getChildren(parent, predicate);

                if (site != null && !ObjectUtils.isBlank(taxonResults)) {

                    Collection<Taxon> siteTaxons = new ArrayList<Taxon>();

                    for (Taxon taxon : taxonResults) {
                        if (PredicateParser.Static.evaluate(taxon, site.itemsPredicate())) {
                            siteTaxons.add(taxon);
                        }
                    }
                    taxonResults = siteTaxons;
                }

            } else {
                taxonResults = Taxon.Static.getRoots((Class<Taxon>) taxonType.getObjectClass(), site, predicate);
            }

            if (!ObjectUtils.isBlank(taxonResults)) {
                resultsDisplayed = true;

                page.writeStart("div", "class", "searchResultList");

                if (level == 1) {
                    page.writeStart("div", "class", "taxonomyContainer");
                    page.writeStart("div", "class", "searchTaxonomy");
                }

                renderTaxonList(taxonResults, nextLevel);

                if (level == 1) {
                    page.writeEnd();
                    page.writeEnd();
                }

                page.writeEnd();
            }
        }

        if (!resultsDisplayed) {
            if (search.findSorts().size() > 1) {
                page.writeStart("div", "class", "searchSorter");
                    renderSorter();
                page.writeEnd();
            }

            page.writeStart("div", "class", "searchPagination");
                renderPagination();
            page.writeEnd();

            page.writeStart("div", "class", "searchResultList");
                if (result.hasPages()) {
                    renderList(result.getItems());
                } else {
                    renderEmpty();
                }
            page.writeEnd();
        }

        if (search.isSuggestions() && ObjectUtils.isBlank(search.getQueryString())) {
            String frameName = page.createId();

            page.writeStart("div", "class", "frame", "name", frameName);
            page.writeEnd();

            page.writeStart("form",
                    "class", "searchSuggestionsForm",
                    "method", "post",
                    "action", page.url("/content/suggestions.jsp"),
                    "target", frameName);
                page.writeElement("input",
                        "type", "hidden",
                        "name", "search",
                        "value", ObjectUtils.toJson(search.getState().getSimpleValues()));
            page.writeEnd();
        }
    }

    private void writeTaxon(Taxon taxon, int nextLevel) throws IOException {
        page.writeStart("li");
            if (taxon.as(Taxon.Data.class).isSelectable()) {
                renderBeforeItem(taxon);
                writeTaxonLabel(taxon);
                renderAfterItem(taxon);
            } else {
                writeTaxonLabel(taxon);
            }

            Predicate predicate = search.toQuery(page.getSite()).getPredicate();
            Collection<? extends Taxon> children = Taxon.Static.getChildren(taxon, predicate);

            if (children != null && !children.isEmpty()) {
                page.writeStart("a",
                        "href", page.url("", TAXON_PARENT_ID_PARAMETER, taxon.as(Taxon.Data.class).getId(), TAXON_LEVEL_PARAMETER, nextLevel),
                        "class", "taxonomyExpand",
                        "target", "taxonChildren-d" + nextLevel);
                page.writeEnd();
            }
        page.writeEnd();
    }

    private void writeTaxonLabel(Taxon taxon) throws IOException {
        if (taxon == null) {
            page.writeHtml("N/A");
        }
        String altLabel = taxon.as(Taxon.Data.class).getAltLabel();
        if (ObjectUtils.isBlank(altLabel)) {
            page.writeObjectLabel(taxon);
        } else {
            String visibilityLabel = taxon.getState().getVisibilityLabel();
            if (!ObjectUtils.isBlank(visibilityLabel)) {
                page.writeStart("span", "class", "visibilityLabel");
                    page.writeHtml(visibilityLabel);
                page.writeEnd();

                page.writeHtml(" ");
            }
            page.writeHtml(altLabel);
        }
    }

    public void renderSorter() throws IOException {
        page.writeStart("form",
                "data-bsp-autosubmit", "",
                "method", "get",
                "action", page.url(null));

            for (Map.Entry<String, List<String>> entry : StringUtils.getQueryParameterMap(page.url("",
                    Search.SORT_PARAMETER, null,
                    Search.SHOW_MISSING_PARAMETER, null,
                    Search.OFFSET_PARAMETER, null)).entrySet()) {
                String name = entry.getKey();

                for (String value : entry.getValue()) {
                    page.writeElement("input", "type", "hidden", "name", name, "value", value);
                }
            }

            page.writeStart("select", "name", Search.SORT_PARAMETER);
                for (Map.Entry<String, String> entry : search.findSorts().entrySet()) {
                    String label = entry.getValue();
                    String value = entry.getKey();

                    page.writeStart("option",
                            "value", value,
                            "selected", value.equals(search.getSort()) ? "selected" : null);
                        page.writeHtml("Sort: ").writeHtml(label);
                    page.writeEnd();
                }
            page.writeEnd();

            if (sortField != null) {
                page.writeHtml(" ");

                page.writeElement("input",
                        "id", page.createId(),
                        "type", "checkbox",
                        "name", Search.SHOW_MISSING_PARAMETER,
                        "value", "true",
                        "checked", search.isShowMissing() ? "checked" : null);

                page.writeHtml(" ");

                page.writeStart("label", "for", page.getId());
                    page.writeHtml("Show Missing");
                page.writeEnd();
            }

        page.writeEnd();
    }

    public void renderPagination() throws IOException {
        page.writeStart("ul", "class", "pagination");

            if (result.hasPrevious()) {
                page.writeStart("li", "class", "previous");
                    page.writeStart("a", "href", page.url("", Search.OFFSET_PARAMETER, result.getPreviousOffset()));
                        page.writeHtml("Previous ");
                        page.writeHtml(result.getLimit());
                    page.writeEnd();
                page.writeEnd();
            }

            page.writeStart("li");
                page.writeHtml(result.getFirstItemIndex());
                page.writeHtml(" to ");
                page.writeHtml(result.getLastItemIndex());
                page.writeHtml(" of ");
                page.writeStart("strong").writeHtml(result.getCount()).writeEnd();
            page.writeEnd();

            if (result.hasNext()) {
                page.writeStart("li", "class", "next");
                    page.writeStart("a", "href", page.url("", Search.OFFSET_PARAMETER, result.getNextOffset()));
                        page.writeHtml("Next ");
                        page.writeHtml(result.getLimit());
                    page.writeEnd();
                page.writeEnd();
            }

        page.writeEnd();
    }

    public void renderList(Collection<?> listItems) throws IOException {
        List<Object> items = new ArrayList<Object>(listItems);
        Map<Object, StorageItem> previews = new LinkedHashMap<Object, StorageItem>();

        ITEM: for (ListIterator<Object> i = items.listIterator(); i.hasNext();) {
            Object item = i.next();

            for (Tool tool : Query.from(Tool.class).selectAll()) {
                if (!tool.isDisplaySearchResultItem(search, item)) {
                    continue ITEM;
                }
            }

            State itemState = State.getInstance(item);
            StorageItem preview = itemState.getPreview();

            if (preview != null) {
                String contentType = preview.getContentType();

                if (contentType != null && contentType.startsWith("image/")) {
                    i.remove();
                    previews.put(item, preview);
                }
            }
        }

        if (!previews.isEmpty()) {
            page.writeStart("div", "class", "searchResultImages");
                for (Map.Entry<Object, StorageItem> entry : previews.entrySet()) {
                    renderImage(entry.getKey(), entry.getValue());
                }
            page.writeEnd();
        }

        if (!items.isEmpty()) {
            page.writeStart("table", "class", "searchResultTable links table-striped pageThumbnails");
                page.writeStart("tbody");
                    for (Object item : items) {
                        renderRow(item);
                    }
                page.writeEnd();
            page.writeEnd();
        }
    }

    public void renderTaxonList(Collection<?> listItems, int nextLevel) throws IOException {
        page.writeStart("ul", "class", "taxonomy");

        for (Taxon taxon : (Collection<Taxon>) listItems) {
            writeTaxon(taxon, nextLevel);
        }

        page.writeEnd();
        page.writeStart("div",
                "class", "frame taxonChildren",
                "name", "taxonChildren-d" + nextLevel);
        page.writeEnd();
    }

    public void renderImage(Object item, StorageItem image) throws IOException {
        renderBeforeItem(item);

        page.writeStart("figure");
            page.writeElement("img",
                    "src", page.getPreviewThumbnailUrl(item),
                    "alt",
                            (showSiteLabel ? page.getObjectLabel(State.getInstance(item).as(Site.ObjectModification.class).getOwner()) + ": " : "") +
                            (showTypeLabel ? page.getTypeLabel(item) + ": " : "") +
                            page.getObjectLabel(item));

            page.writeStart("figcaption");
                if (showSiteLabel) {
                    page.writeObjectLabel(State.getInstance(item).as(Site.ObjectModification.class).getOwner());
                    page.writeHtml(": ");
                }

                if (showTypeLabel) {
                    page.writeTypeLabel(item);
                    page.writeHtml(": ");
                }

                page.writeObjectLabel(item);
            page.writeEnd();
        page.writeEnd();

        renderAfterItem(item);
    }

    public void renderRow(Object item) throws IOException {
        HttpServletRequest request = page.getRequest();
        State itemState = State.getInstance(item);
        String permalink = itemState.as(Directory.ObjectModification.class).getPermalink();
        Integer embedWidth = null;

        if (ObjectUtils.isBlank(permalink)) {
            ObjectType type = itemState.getType();

            if (type != null) {
                Renderer.TypeModification rendererData = type.as(Renderer.TypeModification.class);
                int previewWidth = rendererData.getEmbedPreviewWidth();

                if (previewWidth > 0 &&
                        !ObjectUtils.isBlank(rendererData.getEmbedPath())) {
                    permalink = "/_preview?_embed=true&_cms.db.previewId=" + itemState.getId();
                    embedWidth = 320;
                }
            }
        }

        page.writeStart("tr",
                "data-preview-url", permalink,
                "data-preview-embed-width", embedWidth,
                "class", State.getInstance(item).getId().equals(page.param(UUID.class, "id")) ? "selected" : null);

            if (sortField != null &&
                    ObjectField.DATE_TYPE.equals(sortField.getInternalType())) {
                DateTime dateTime = page.toUserDateTime(itemState.get(sortField.getInternalName()));

                if (dateTime == null) {
                    page.writeStart("td", "colspan", 2);
                        page.writeHtml("N/A");
                    page.writeEnd();

                } else {
                    String date = page.formatUserDate(dateTime);

                    page.writeStart("td", "class", "date");
                        if (!ObjectUtils.equals(date, request.getAttribute(PREVIOUS_DATE_ATTRIBUTE))) {
                            request.setAttribute(PREVIOUS_DATE_ATTRIBUTE, date);
                            page.writeHtml(date);
                        }
                    page.writeEnd();

                    page.writeStart("td", "class", "time");
                        page.writeHtml(page.formatUserTime(dateTime));
                    page.writeEnd();
                }
            }

            if (showSiteLabel) {
                page.writeStart("td");
                    page.writeObjectLabel(itemState.as(Site.ObjectModification.class).getOwner());
                page.writeEnd();
            }

            if (showTypeLabel) {
                page.writeStart("td");
                    page.writeTypeLabel(item);
                page.writeEnd();
            }

            page.writeStart("td", "data-preview-anchor", "");
                renderBeforeItem(item);
                page.writeObjectLabel(item);
                renderAfterItem(item);
            page.writeEnd();

            if (sortField != null &&
                    !ObjectField.DATE_TYPE.equals(sortField.getInternalType())) {
                String sortFieldName = sortField.getInternalName();
                Object value = itemState.get(sortFieldName);

                page.writeStart("td");
                    if (value instanceof Metric) {
                        page.writeStart("span", "style", page.cssString("white-space", "nowrap"));
                            Double maxSum = (Double) request.getAttribute(MAX_SUM_ATTRIBUTE);

                            if (maxSum == null) {
                                Object maxObject = search.toQuery(page.getSite()).sortDescending(sortFieldName).first();
                                maxSum = maxObject != null ?
                                        ((Metric) State.getInstance(maxObject).get(sortFieldName)).getSum() :
                                        1.0;

                                request.setAttribute(MAX_SUM_ATTRIBUTE, maxSum);
                            }

                            Metric valueMetric = (Metric) value;
                            Map<DateTime, Double> sumEntries = valueMetric.groupSumByDate(
                                    new MetricInterval.Daily(),
                                    new DateTime().dayOfMonth().roundFloorCopy().minusDays(7),
                                    null);

                            double sum = valueMetric.getSum();
                            long sumLong = (long) sum;

                            if (sumLong == sum) {
                                page.writeHtml(String.format("%,2d ", sumLong));

                            } else {
                                page.writeHtml(String.format("%,2.2f ", sum));
                            }

                            if (!sumEntries.isEmpty()) {
                                long minMillis = Long.MAX_VALUE;
                                long maxMillis = Long.MIN_VALUE;

                                for (Map.Entry<DateTime, Double> sumEntry : sumEntries.entrySet()) {
                                    long sumMillis = sumEntry.getKey().getMillis();

                                    if (sumMillis < minMillis) {
                                        minMillis = sumMillis;
                                    }

                                    if (sumMillis > maxMillis) {
                                        maxMillis = sumMillis;
                                    }
                                }

                                double cumulativeSum = 0.0;
                                StringBuilder path = new StringBuilder();
                                double xRange = maxMillis - minMillis;
                                int width = 35;
                                int height = 18;

                                for (Map.Entry<DateTime, Double> sumEntry : sumEntries.entrySet()) {
                                    cumulativeSum += sumEntry.getValue();

                                    path.append('L');
                                    path.append((sumEntry.getKey().getMillis() - minMillis) / xRange * width);
                                    path.append(',');
                                    path.append(height - cumulativeSum / maxSum * height);
                                }

                                path.setCharAt(0, 'M');

                                page.writeStart("svg",
                                        "xmlns", "http://www.w3.org/2000/svg",
                                        "width", width,
                                        "height", height,
                                        "style", page.cssString(
                                                "display", "inline-block",
                                                "vertical-align", "middle"));
                                    page.writeStart("path",
                                            "fill", "none",
                                            "stroke", "#444444",
                                            "d", path.toString());
                                    page.writeEnd();
                                page.writeEnd();
                            }
                        page.writeEnd();

                    } else if (value instanceof Recordable) {
                        page.writeHtml(((Recordable) value).getState().getLabel());

                    } else {
                        page.writeHtml(value);
                    }
                page.writeEnd();
            }

        page.writeEnd();
    }

    public void renderBeforeItem(Object item) throws IOException {
        page.writeStart("a",
                "href", page.toolUrl(CmsTool.class, "/content/edit.jsp",
                        "id", State.getInstance(item).getId(),
                        "search", page.url("", Search.NAME_PARAMETER, null)),
                "data-objectId", State.getInstance(item).getId(),
                "target", "_top");
    }

    public void renderAfterItem(Object item) throws IOException {
        page.writeEnd();
    }

    public void renderEmpty() throws IOException {
        page.writeStart("div", "class", "message message-warning");
            page.writeStart("p");
                page.writeHtml("No matching items!");
            page.writeEnd();
        page.writeEnd();
    }
}
TOP

Related Classes of com.psddev.cms.tool.SearchResultRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.