How to make p:dashboard components draggable witho

2019-02-26 00:17发布

问题:

As a follow up to this question. It appears the components in a p:dashboard are only draggable if their parent panel has a header set (which contains the title). How do I make it so the panels can be dragged even if the header isn't set? So the whole panel will be the handle to drag it around, not just the header.

XHTML

<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:p="http://primefaces.org/ui">
<h:head>
    <title>Example</title>
</h:head>
<h:body>
    <h:form id="splitButtonForm">
        <p:splitButton value="Action" icon="ui-icon-circle-triangle-s">
            <p:menuitem value="New text entry" icon="ui-icon-newwin"
                actionListener="#{dashboardView.addTextWidget}"
                update="dashboardForm:dashboardPanel" />
        </p:splitButton>
    </h:form>

    <div style="height: 500px">
        <h:form id="dashboardForm">
            <p:dashboard id="dashboardPanel" model="#{dashboardView.model}"
                binding="#{dashboardView.dashboardPanel }">
                <p:ajax event="reorder" />
            </p:dashboard>
            <div style="clear: both" />
        </h:form>
    </div>
</h:body>
</html>

And the bean

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIComponent;
import javax.faces.event.ActionEvent;

import org.primefaces.component.inputtext.InputText;
import org.primefaces.component.panel.Panel;
import org.primefaces.model.DashboardColumn;
import org.primefaces.model.DashboardModel;
import org.primefaces.model.DefaultDashboardColumn;
import org.primefaces.model.DefaultDashboardModel;

@SuppressWarnings("serial")
@ManagedBean
@ViewScoped
public class DashboardView implements Serializable
{

    private DashboardModel model;

    private UIComponent dashboardPanel;

    public void addTextWidget(ActionEvent event)
    {

        Panel panel = new Panel();

        InputText textWidget = new InputText();

        int childCount = dashboardPanel.getChildCount();

        String widgetId = "widget" + String.valueOf(childCount);

        panel.setHeader(widgetId); //I don't want to have to do this

        panel.setId(widgetId);
        panel.getChildren().add(textWidget);

        addWidget(widgetId);

        dashboardPanel.getChildren().add(panel);
    }

    public void addWidget(String widgetId)
    {
        DashboardColumn column1 = model.getColumn(0);
        column1.addWidget(widgetId);
    }

    public UIComponent getDashboardPanel()
    {
        return dashboardPanel;
    }

    public DashboardModel getModel()
    {
        return model;
    }

    @PostConstruct
    public void init()
    {
        model = new DefaultDashboardModel();
        DashboardColumn column1 = new DefaultDashboardColumn();
        DashboardColumn column2 = new DefaultDashboardColumn();

        model.addColumn(column1);
        model.addColumn(column2);
    }

    public void setDashboardPanel(UIComponent dashboardPanel)
    {
        this.dashboardPanel = dashboardPanel;
    }

}

回答1:

Kukeltje had it right, basically it comes down to the handle property being hardcoded in the JS PrimeFaces.widget.Dashboard init function. I created my own javascript file with the same code but without the handle property set and then included that script after the h:body using h:outputScript

Here's the javascript

PrimeFaces.widget.Dashboard = PrimeFaces.widget.BaseWidget
        .extend({
            init : function(b) {
                this._super(b);
                this.cfg.connectWith = this.jqId + " .ui-dashboard-column";
                this.cfg.placeholder = "ui-state-hover";
                this.cfg.forcePlaceholderSize = true;
                this.cfg.revert = false;

                var a = this;
                if (this.cfg.behaviors) {
                    var c = this.cfg.behaviors.reorder;
                    if (c) {
                        this.cfg.update = function(h, g) {
                            if (this === g.item.parent()[0]) {
                                var f = g.item.parent().children().filter(
                                        ":not(script):visible").index(g.item), i = g.item
                                        .parent().parent().children().index(
                                                g.item.parent());
                                var d = {
                                    params : [ {
                                        name : a.id + "_reordered",
                                        value : true
                                    }, {
                                        name : a.id + "_widgetId",
                                        value : g.item.attr("id")
                                    }, {
                                        name : a.id + "_itemIndex",
                                        value : f
                                    }, {
                                        name : a.id + "_receiverColumnIndex",
                                        value : i
                                    } ]
                                };
                                if (g.sender) {
                                    d.params.push({
                                        name : a.id + "_senderColumnIndex",
                                        value : g.sender.parent().children()
                                                .index(g.sender)
                                    })
                                }
                                c.call(a, d)
                            }
                        }
                    }
                }
                $(this.jqId + " .ui-dashboard-column").sortable(this.cfg)
            }
        });

And the relevant part of the XHTML

<h:body>
    <h:outputScript library="js" name="pfaces.js" />
    ...
</h:body>