001package gwt.material.design.addins.client.dnd;
002
003/*
004 * #%L
005 * GwtMaterial
006 * %%
007 * Copyright (C) 2015 - 2016 GwtMaterialDesign
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023
024import com.google.gwt.dom.client.Document;
025import com.google.gwt.dom.client.Element;
026import com.google.gwt.event.logical.shared.AttachEvent;
027import com.google.gwt.event.shared.HandlerRegistration;
028import com.google.gwt.user.client.ui.Widget;
029import gwt.material.design.addins.client.MaterialAddins;
030import gwt.material.design.addins.client.dnd.base.HasDraggable;
031import gwt.material.design.addins.client.dnd.constants.Restriction;
032import gwt.material.design.addins.client.dnd.events.DragEndEvent;
033import gwt.material.design.addins.client.dnd.events.DragMoveEvent;
034import gwt.material.design.addins.client.dnd.events.DragStartEvent;
035import gwt.material.design.client.MaterialDesignBase;
036import gwt.material.design.client.base.MaterialWidget;
037
038//@formatter:off
039/**
040 * Drag and drop feature on Material Design specs are great UX guide to
041 * provide a delightful motion on dragging and dropping gestures.
042 *
043 * <h3>Java Usage</h3>
044 * <pre>
045 *{@code
046 *
047 * MaterialDnd dnd = new MaterialDnd();
048 * // Set the draggable object
049 * dnd.setDraggable(widget);
050 *
051 * // Set the ignored widget when dragging the element
052 * dnd.setIgnoreFrom(toolbar);
053 *
054 * }
055 * </pre>
056 *
057 * @author kevzlou7979
058 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#dnd">Drag and Drop</a>
059 */
060//@formatter:on
061public class MaterialDnd extends MaterialWidget implements HasDraggable {
062
063    static {
064        if(MaterialAddins.isDebug()) {
065            MaterialDesignBase.injectDebugJs(MaterialDndDebugClientBundle.INSTANCE.dndDebugJs());
066        } else {
067            MaterialDesignBase.injectJs(MaterialDndClientBundle.INSTANCE.dndJs());
068        }
069
070    }
071
072    private boolean inertia;
073    private Widget target;
074    private Widget ignoreFrom;
075    private Restriction restriction = new Restriction();
076
077    public MaterialDnd() {
078        super(Document.get().createDivElement());
079    }
080
081    public boolean isInertia() {
082        return inertia;
083    }
084
085    public void setInertia(boolean inertia) {
086        this.inertia = inertia;
087    }
088
089    @Override
090    public void setTarget(final Widget target) {
091        this.target = target;
092        if(!target.isAttached()) {
093            target.addAttachHandler(new AttachEvent.Handler() {
094                @Override
095                public void onAttachOrDetach(AttachEvent event) {
096                    if(event.isAttached()) {
097                        initDraggable(target.getElement(), isInertia(), restriction.getRestriction().getValue(), restriction.isEndOnly(),
098                                restriction.getTop(), restriction.getLeft(), restriction.getBottom(), restriction.getRight());
099                    }
100                }
101            });
102        } else {
103            initDraggable(target.getElement(), isInertia(), restriction.getRestriction().getValue(), restriction.isEndOnly(),
104                    restriction.getTop(), restriction.getLeft(), restriction.getBottom(), restriction.getRight());
105        }
106    }
107
108    /**
109     * Initialize the draggable widget and it's properties
110     * @param target
111     */
112    protected native void initDraggable(Element target, boolean inertia, String restriction, boolean endOnly,
113                                      double top, double left, double bottom, double right) /*-{
114        var that = this;
115        $wnd.jQuery(document).ready(function() {
116            $wnd.interact(target)
117                .draggable({
118                    inertia: inertia,
119                    restrict: {
120                        restriction: restriction,
121                        endOnly: endOnly,
122                        elementRect: { top: top, left: left, bottom: bottom, right: right}
123                    },
124                    onstart: dragStartListener,
125                    onmove: dragMoveListener,
126                    onend: dragEndListener,
127                });
128
129            function dragEndListener(event) {
130                that.@gwt.material.design.addins.client.dnd.MaterialDnd::fireDragEndEvent()();
131            }
132
133            function dragStartListener(event) {
134                that.@gwt.material.design.addins.client.dnd.MaterialDnd::fireDragStartEvent()();
135            }
136
137            function dragMoveListener (event) {
138                var target = event.target,
139                    x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
140                    y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
141
142                target.style.webkitTransform =
143                    target.style.transform =
144                        'translate(' + x + 'px, ' + y + 'px)';
145
146                target.setAttribute('data-x', x);
147                target.setAttribute('data-y', y);
148                that.@gwt.material.design.addins.client.dnd.MaterialDnd::fireDragMoveEvent()();
149            }
150        });
151    }-*/;
152
153    @Override
154    public Widget getTarget() {
155        return target;
156    }
157
158    @Override
159    public void setIgnoreFrom(final Widget ignoreFrom) {
160        this.ignoreFrom = ignoreFrom;
161        if(!target.isAttached() && !ignoreFrom.isAttached()) {
162            ignoreFrom.addAttachHandler(new AttachEvent.Handler() {
163                @Override
164                public void onAttachOrDetach(AttachEvent event) {
165                    if(event.isAttached()) {
166                        initIgnoreFrom(target.getElement(), ignoreFrom.getElement());
167                    }
168                }
169            });
170        }else {
171            initIgnoreFrom(target.getElement(), ignoreFrom.getElement());
172        }
173    }
174
175    @Override
176    public void setIgnoreFrom(final String selector) {
177        if(!target.isAttached()){
178            target.addAttachHandler(new AttachEvent.Handler() {
179                @Override
180                public void onAttachOrDetach(AttachEvent event) {
181                    initIgnoreFrom(target.getElement(), selector);
182                }
183            });
184        } else {
185            initIgnoreFrom(target.getElement(), selector);
186        }
187    }
188
189    /**
190     * Initialize the ignoreFrom function as selector to exclude any widget from dragging
191     */
192    protected native void initIgnoreFrom(Element target, String selector) /*-{
193        $wnd.interact(target).ignoreFrom(selector);
194    }-*/;
195
196    /**
197     * Initialize the ignoreFrom function to exclude any widget from dragging
198     */
199    protected native void initIgnoreFrom(Element target, Element ignoreFrom) /*-{
200        $wnd.interact(target).ignoreFrom(ignoreFrom);
201    }-*/;
202
203    @Override
204    public Widget isIgnoreFrom() {
205        return ignoreFrom;
206    }
207
208    @Override
209    public void setRestriction(Restriction restriction) {
210        this.restriction = restriction;
211    }
212
213    @Override
214    public Restriction getRestriction() {
215        return restriction;
216    }
217
218    @Override
219    public HandlerRegistration addDragStartHandler(final DragStartEvent.DragStartHandler handler) {
220        return addHandler(new DragStartEvent.DragStartHandler() {
221            @Override
222            public void onDragStart(DragStartEvent event) {
223                if(isEnabled()){
224                    handler.onDragStart(event);
225                }
226            }
227        }, DragStartEvent.TYPE);
228    }
229
230    protected void fireDragStartEvent() {
231        DragStartEvent.fire(this);
232    }
233
234    @Override
235    public HandlerRegistration addDragMoveHandler(final DragMoveEvent.DragMoveHandler handler) {
236        return addHandler(new DragMoveEvent.DragMoveHandler() {
237            @Override
238            public void onDragMove(DragMoveEvent event) {
239                if(isEnabled()){
240                    handler.onDragMove(event);
241                }
242            }
243        }, DragMoveEvent.TYPE);
244    }
245
246    protected void fireDragMoveEvent() {
247        DragMoveEvent.fire(this);
248    }
249
250    @Override
251    public HandlerRegistration addDragEndHandler(final DragEndEvent.DragEndHandler handler) {
252        return addHandler(new DragEndEvent.DragEndHandler() {
253            @Override
254            public void onDragEnd(DragEndEvent event) {
255                if(isEnabled()){
256                    handler.onDragEnd(event);
257                }
258            }
259        }, DragEndEvent.TYPE);
260    }
261
262    protected void fireDragEndEvent() {
263        DragEndEvent.fire(this);
264    }
265}