001/* 002 * #%L 003 * GwtMaterial 004 * %% 005 * Copyright (C) 2015 - 2017 GwtMaterialDesign 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package gwt.material.design.addins.client.dnd; 021 022import com.google.gwt.dom.client.Element; 023import com.google.gwt.user.client.ui.UIObject; 024import gwt.material.design.addins.client.MaterialAddins; 025import gwt.material.design.addins.client.dnd.constants.DragEvents; 026import gwt.material.design.addins.client.dnd.constants.DropEvents; 027import gwt.material.design.addins.client.dnd.js.JsDnd; 028import gwt.material.design.addins.client.dnd.js.JsDragOptions; 029import gwt.material.design.addins.client.dnd.js.JsDropOptions; 030import gwt.material.design.client.MaterialDesignBase; 031import gwt.material.design.client.base.MaterialWidget; 032import gwt.material.design.client.events.*; 033import gwt.material.design.jquery.client.api.Event; 034import gwt.material.design.jquery.client.api.JQuery; 035 036//@formatter:off 037 038/** 039 * Drag and drop feature on Material Design specs are great UX guide to 040 * provide a delightful motion on dragging and dropping gestures. 041 * <p> 042 * <h3>Java Usage</h3> 043 * <pre> 044 * {@code 045 * 046 * MaterialDnd dnd = new MaterialDnd(); 047 * // Set the draggable object 048 * dnd.setDraggable(widget); 049 * 050 * // Set the ignored widget when dragging the element 051 * dnd.setIgnoreFrom(toolbar); 052 * 053 * } 054 * </pre> 055 * 056 * @author kevzlou7979 057 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#dnd">Drag and Drop</a> 058 * @see <a href="https://github.com/taye/interact.js">InteractJs 1.2.6</a> 059 */ 060//@formatter:on 061public class MaterialDnd { 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 private JsDnd jsDnd; 072 private final MaterialWidget target; 073 private Element[] ignoreFrom; 074 private JsDropOptions dropOptions; 075 private JsDragOptions dragOptions; 076 077 protected MaterialDnd(MaterialWidget target) { 078 this.target = target; 079 } 080 081 protected MaterialDnd draggable() { 082 if (jsDnd == null) { 083 jsDnd = JsDnd.interact(target.getElement()); 084 085 // Events 086 jsDnd.off(DragEvents.DRAG_MOVE).on(DragEvents.DRAG_MOVE, event -> { 087 move(event); 088 DragMoveEvent.fire(this.target); 089 return true; 090 }); 091 jsDnd.off(DragEvents.DRAG_START).on(DragEvents.DRAG_START, event -> { 092 DragStartEvent.fire(this.target); 093 return true; 094 }); 095 jsDnd.off(DragEvents.DRAG_END).on(DragEvents.DRAG_END, event -> { 096 DragEndEvent.fire(this.target); 097 return true; 098 }); 099 } 100 jsDnd.draggable(dragOptions); 101 return this; 102 } 103 104 public MaterialDnd draggable(JsDragOptions options) { 105 dragOptions = options; 106 if (target.isAttached()) { 107 draggable(); 108 } else { 109 target.registerHandler(target.addAttachHandler(event -> draggable(), true)); 110 } 111 return this; 112 } 113 114 public static MaterialDnd draggable(MaterialWidget target) { 115 return draggable(target, JsDragOptions.create()); 116 } 117 118 public static MaterialDnd draggable(MaterialWidget target, JsDragOptions options) { 119 return new MaterialDnd(target).draggable(options); 120 } 121 122 protected MaterialDnd dropzone() { 123 if (jsDnd == null) { 124 jsDnd = JsDnd.interact(target.getElement()); 125 126 // Events 127 jsDnd.off(DropEvents.DROP_ACTIVATE).on(DropEvents.DROP_ACTIVATE, event -> { 128 DropActivateEvent.fire(this.target); 129 return true; 130 }); 131 jsDnd.off(DragEvents.DRAG_ENTER).on(DragEvents.DRAG_ENTER, event -> { 132 DragEnterEvent.fire(this.target, event.getRelatedTarget()); 133 return true; 134 }); 135 jsDnd.off(DragEvents.DRAG_LEAVE).on(DragEvents.DRAG_LEAVE, event -> { 136 DragLeaveEvent.fire(this.target, event.getRelatedTarget()); 137 return true; 138 }); 139 jsDnd.off(DropEvents.DROP).on(DropEvents.DROP, event -> { 140 DropEvent.fire(this.target, event.getRelatedTarget()); 141 return true; 142 }); 143 jsDnd.off(DropEvents.DROP_DEACTIVATE).on(DropEvents.DROP_DEACTIVATE, event -> { 144 DropDeactivateEvent.fire(this.target); 145 return true; 146 }); 147 } 148 149 jsDnd.dropzone(dropOptions); 150 return this; 151 } 152 153 public MaterialDnd dropzone(JsDropOptions options) { 154 dropOptions = options; 155 if (target.isAttached()) { 156 dropzone(); 157 } else { 158 target.registerHandler(target.addAttachHandler(event -> dropzone(), true)); 159 } 160 return this; 161 } 162 163 public static MaterialDnd dropzone(MaterialWidget target) { 164 return dropzone(target, JsDropOptions.create()); 165 } 166 167 public static MaterialDnd dropzone(MaterialWidget target, JsDropOptions options) { 168 return new MaterialDnd(target).dropzone(options); 169 } 170 171 public void ignoreFrom(UIObject uiObject) { 172 ignoreFrom(uiObject.getElement()); 173 } 174 175 public void ignoreFrom(Element... elements) { 176 this.ignoreFrom = elements; 177 if (target.isAttached()) { 178 for (Element element : ignoreFrom) { 179 JsDnd.interact(target.getElement()).ignoreFrom(element); 180 } 181 } else { 182 target.registerHandler(target.addAttachHandler(event -> { 183 for (Element element : ignoreFrom) { 184 JsDnd.interact(target.getElement()).ignoreFrom(element); 185 } 186 }, true)); 187 } 188 } 189 190 public void ignoreFrom(String selector) { 191 this.ignoreFrom = new Element[]{JQuery.$(selector).asElement()}; 192 if (target.isAttached()) { 193 JsDnd.interact(target.getElement()).ignoreFrom(selector); 194 } else { 195 target.registerHandler(target.addAttachHandler(event -> JsDnd.interact(target.getElement()).ignoreFrom(selector), true)); 196 } 197 } 198 199 public MaterialWidget getTarget() { 200 return target; 201 } 202 203 public Element[] getIgnoreFrom() { 204 return ignoreFrom; 205 } 206 207 public JsDropOptions getDropOptions() { 208 return dropOptions; 209 } 210 211 public JsDragOptions getDragOptions() { 212 return dragOptions; 213 } 214 215 public static native void move(Event event) /*-{ 216 var target = event.target, 217 x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx, 218 y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy; 219 220 target.style.webkitTransform = 221 target.style.transform = 222 'translate(' + x + 'px, ' + y + 'px)'; 223 224 target.setAttribute('data-x', x); 225 target.setAttribute('data-y', y); 226 }-*/; 227}