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}