You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2018/08/08 04:38:17 UTC
[openmeetings] branch master updated: [OPENMEETINGS-1919] drag and
drop should work better
This is an automated email from the ASF dual-hosted git repository.
solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git
The following commit(s) were added to refs/heads/master by this push:
new 0641d7a [OPENMEETINGS-1919] drag and drop should work better
0641d7a is described below
commit 0641d7a695c2d476c208e355903da783ec308d6b
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Wed Aug 8 11:35:29 2018 +0700
[OPENMEETINGS-1919] drag and drop should work better
---
.../web/common/tree/FileItemPanel.java | 4 +-
.../openmeetings/web/common/tree/FileItemTree.java | 162 +------------
.../openmeetings/web/common/tree/FolderPanel.html | 2 +-
.../openmeetings/web/common/tree/FolderPanel.java | 260 ++++++++++++++++-----
openmeetings-web/src/main/webapp/css/raw-tree.css | 5 +-
5 files changed, 209 insertions(+), 224 deletions(-)
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileItemPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileItemPanel.java
index 226577a..6d1273d 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileItemPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileItemPanel.java
@@ -36,7 +36,7 @@ public class FileItemPanel extends FolderPanel {
@SpringBean
private FileItemLogDao fileLogDao;
- public FileItemPanel(String id, final IModel<? extends BaseFileItem> model, final FileTreePanel fileTreePanel) {
+ public FileItemPanel(String id, final IModel<BaseFileItem> model, final FileTreePanel fileTreePanel) {
super(id, model, fileTreePanel);
BaseFileItem f = model.getObject();
long errorCount = fileLogDao.countErrors(f);
@@ -56,6 +56,6 @@ public class FileItemPanel extends FolderPanel {
fileTreePanel.errorsDialog.open(target);
}
}).setVisible(visible);
- drag.add(errors);
+ add(errors);
}
}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileItemTree.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileItemTree.java
index 9cc8c73..52614d4 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileItemTree.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileItemTree.java
@@ -18,33 +18,17 @@
*/
package org.apache.openmeetings.web.common.tree;
-import java.util.Optional;
-
import org.apache.openmeetings.db.entity.file.BaseFileItem;
import org.apache.openmeetings.db.entity.file.BaseFileItem.Type;
-import org.apache.openmeetings.db.entity.record.Recording;
-import org.apache.openmeetings.db.entity.record.Recording.Status;
import org.apache.wicket.Component;
-import org.apache.wicket.MarkupContainer;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
-import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.extensions.markup.html.repeater.tree.DefaultNestedTree;
import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
-import org.apache.wicket.extensions.markup.html.repeater.tree.content.Folder;
import org.apache.wicket.markup.repeater.ReuseIfModelsEqualStrategy;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
-import org.apache.wicket.util.string.Strings;
-
-import com.github.openjson.JSONObject;
public class FileItemTree extends DefaultNestedTree<BaseFileItem> {
private static final long serialVersionUID = 1L;
- private static final String CSS_CLASS_FILE = "file ";
- private static final String PARAM_MOD = "mod";
- private static final String PARAM_SHIFT = "s";
- private static final String PARAM_CTRL = "c";
final FileTreePanel treePanel;
public FileItemTree(String id, FileTreePanel treePanel, ITreeProvider<BaseFileItem> tp) {
@@ -53,26 +37,6 @@ public class FileItemTree extends DefaultNestedTree<BaseFileItem> {
setItemReuseStrategy(new ReuseIfModelsEqualStrategy());
}
- private void onClick(AjaxRequestTarget target, BaseFileItem f) {
- String mod = getRequest().getRequestParameters().getParameterValue(PARAM_MOD).toOptionalString();
- boolean shift = false, ctrl = false;
- if (!Strings.isEmpty(mod)) {
- JSONObject o = new JSONObject(mod);
- shift = o.optBoolean(PARAM_SHIFT);
- ctrl = o.optBoolean(PARAM_CTRL);
- }
- treePanel.select(f, target, shift, ctrl);
- if (Type.Folder == f.getType() && getState(f) == State.COLLAPSED) {
- this.expand(f);
- } else {
- treePanel.update(target, f);
- }
- }
-
- private static boolean isClickable() {
- return true;
- }
-
@Override
public OmTreeProvider getProvider() {
return (OmTreeProvider)super.getProvider();
@@ -87,126 +51,10 @@ public class FileItemTree extends DefaultNestedTree<BaseFileItem> {
}
@Override
- protected Component newContentComponent(String id, IModel<BaseFileItem> node) {
- return new Folder<BaseFileItem>(id, this, node) {
- private static final long serialVersionUID = 1L;
-
- @Override
- protected Component newLabelComponent(String id, final IModel<BaseFileItem> lm) {
- BaseFileItem r = lm.getObject();
- return Type.Folder == r.getType() || r.getId() == null
- ? new FolderPanel(id, lm, treePanel)
- : new FileItemPanel(id, lm, treePanel);
- }
-
- @Override
- protected boolean isSelected() {
- return treePanel.isSelected(getModelObject());
- }
-
- @Override
- protected boolean isClickable() {
- return FileItemTree.isClickable();
- }
-
- @Override
- protected void onClick(Optional<AjaxRequestTarget> targetOptional) {
- FileItemTree.this.onClick(targetOptional.get(), getModelObject());
- }
-
- @Override
- protected MarkupContainer newLinkComponent(String id, IModel<BaseFileItem> model) {
- final BaseFileItem f = getModelObject();
- return new AjaxLink<Void>(id) {
- private static final long serialVersionUID = 1L;
-
- @Override
- public boolean isEnabled() {
- return FileItemTree.isClickable();
- }
-
- @Override
- public void onClick(AjaxRequestTarget target) {
- FileItemTree.this.onClick(target, f);
- }
-
- @Override
- protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
- super.updateAjaxAttributes(attributes);
- attributes.getDynamicExtraParameters().add(
- String.format("return {%s: JSON.stringify({%s: attrs.event.shiftKey, %s: attrs.event.ctrlKey})};"
- , PARAM_MOD, PARAM_SHIFT, PARAM_CTRL));
- }
- };
- }
-
- @Override
- protected String getOtherStyleClass(BaseFileItem r) {
- return getItemStyle(r, false);
- }
-
- @Override
- protected String getOpenStyleClass() {
- return getItemStyle(getModelObject(), true);
- }
-
- @Override
- protected String getClosedStyleClass() {
- return getItemStyle(getModelObject(), false);
- }
-
- @Override
- protected String getSelectedStyleClass() {
- return "ui-state-active";
- }
-
- @Override
- protected IModel<String> newLabelModel(IModel<BaseFileItem> model) {
- return Model.of(model.getObject().getName());
- }
- };
- }
-
- private static String getItemStyle(BaseFileItem f, boolean open) {
- StringBuilder style = new StringBuilder("big om-icon ");
- if (f.getId() == null) {
- style.append(CSS_CLASS_FILE).append(f.getHash().indexOf("my") > -1 ? "my" : "public");
- } else {
- if (!f.exists()) {
- style.append("broken ");
- }
- switch(f.getType()) {
- case Folder:
- style.append(CSS_CLASS_FILE).append(open ? "folder-open " : "folder ");
- break;
- case Image:
- style.append(CSS_CLASS_FILE).append("image ");
- break;
- case PollChart:
- style.append(CSS_CLASS_FILE).append("chart ");
- break;
- case WmlFile:
- style.append(CSS_CLASS_FILE).append("wml ");
- break;
- case Video:
- case Recording:
- {
- style.append("recording ");
- if (f instanceof Recording) {
- Status st = ((Recording)f).getStatus();
- if (Status.RECORDING == st || Status.CONVERTING == st) {
- style.append("processing");
- }
- }
- }
- break;
- case Presentation:
- style.append(CSS_CLASS_FILE).append("doc ");
- break;
- default:
- break;
- }
- }
- return style.toString();
+ protected Component newContentComponent(String id, IModel<BaseFileItem> lm) {
+ BaseFileItem r = lm.getObject();
+ return Type.Folder == r.getType() || r.getId() == null
+ ? new FolderPanel(id, lm, treePanel)
+ : new FileItemPanel(id, lm, treePanel);
}
}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FolderPanel.html b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FolderPanel.html
index 8dba394..1b8b067 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FolderPanel.html
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FolderPanel.html
@@ -20,6 +20,6 @@
-->
<html xmlns:wicket="http://wicket.apache.org">
<wicket:panel>
- <div wicket:id="drop" class="file item"><div wicket:id="drag"><wicket:child /><span wicket:id="name" class="name"></span></div></div>
+ <div class="file item"><wicket:child /><span wicket:id="name" class="name"></span></div>
</wicket:panel>
</html>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FolderPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FolderPanel.java
index 5d60d52..465b839 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FolderPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FolderPanel.java
@@ -29,81 +29,76 @@ import org.apache.openmeetings.db.entity.file.BaseFileItem;
import org.apache.openmeetings.db.entity.file.BaseFileItem.Type;
import org.apache.openmeetings.db.entity.file.FileItem;
import org.apache.openmeetings.db.entity.record.Recording;
+import org.apache.openmeetings.db.entity.record.Recording.Status;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
-import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.extensions.ajax.markup.html.AjaxEditableLabel;
-import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree.State;
+import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.apache.wicket.util.string.Strings;
-import com.googlecode.wicket.jquery.core.JQueryBehavior;
+import com.github.openjson.JSONObject;
+import com.googlecode.wicket.jquery.core.IJQueryWidget.JQueryWidget;
import com.googlecode.wicket.jquery.core.Options;
-import com.googlecode.wicket.jquery.ui.interaction.draggable.Draggable;
-import com.googlecode.wicket.jquery.ui.interaction.droppable.Droppable;
+import com.googlecode.wicket.jquery.ui.interaction.draggable.DraggableBehavior;
+import com.googlecode.wicket.jquery.ui.interaction.draggable.IDraggableListener;
+import com.googlecode.wicket.jquery.ui.interaction.droppable.DroppableBehavior;
+import com.googlecode.wicket.jquery.ui.interaction.droppable.IDroppableListener;
-public class FolderPanel extends Panel {
+public class FolderPanel extends Panel implements IDraggableListener, IDroppableListener {
private static final long serialVersionUID = 1L;
- protected final MarkupContainer drop;
- protected final MarkupContainer drag;
+ private static final String CSS_CLASS_FILE = "file ";
+ private static final String PARAM_MOD = "mod";
+ private static final String PARAM_SHIFT = "s";
+ private static final String PARAM_CTRL = "c";
+ private final StyleBehavior styleClass;
+ private final FileTreePanel treePanel;
@SpringBean
private RecordingDao recDao;
@SpringBean
private FileItemDao fileDao;
- public FolderPanel(String id, final IModel<? extends BaseFileItem> model, final FileTreePanel treePanel) {
+ public FolderPanel(String id, final IModel<BaseFileItem> model, final FileTreePanel treePanel) {
super(id, model);
- BaseFileItem r = model.getObject();
- boolean editable = !treePanel.isReadOnly() && !r.isReadOnly();
- drop = r.getType() == Type.Folder && editable ? new Droppable<BaseFileItem>("drop", Model.of(r)) {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void onConfigure(JQueryBehavior behavior) {
- super.onConfigure(behavior);
- behavior.setOption("hoverClass", Options.asString("ui-state-hover"));
- behavior.setOption("accept", Options.asString(getDefaultModelObject() instanceof Recording ? ".recorditem" : ".fileitem"));
- }
+ this.treePanel = treePanel;
+ styleClass = new StyleBehavior();
+ }
- @Override
- public void onDrop(AjaxRequestTarget target, Component component) {
- Object o = component.getDefaultModelObject();
- if (o instanceof BaseFileItem) {
- BaseFileItem p = (BaseFileItem)drop.getDefaultModelObject();
- BaseFileItem f = (BaseFileItem)o;
- if (treePanel.isSelected(f)) {
- moveAll(treePanel, target, p);
- } else {
- move(treePanel, target, p, f);
- }
- treePanel.updateNode(target, p);
- }
- target.add(treePanel.trees);
- }
- } : new WebMarkupContainer("drop");
- if (r.getId() == null || treePanel.isReadOnly()) {
- drag = new WebMarkupContainer("drag");
- } else {
- drag = new Draggable<BaseFileItem>("drag", Model.of(r)) {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void onConfigure(JQueryBehavior behavior) {
- super.onConfigure(behavior);
- behavior.setOption("revert", "treeRevert");
- behavior.setOption("cursor", Options.asString("move"));
- behavior.setOption("helper", "dragHelper");
- behavior.setOption("cursorAt", "{left: 40, top: 18}");
- }
- }.setContainment(treePanel.getContainment());
- String cls = r instanceof Recording ? "recorditem" : "fileitem";
- drag.add(AttributeModifier.append(ATTR_CLASS, r.isReadOnly() ? "readonlyitem" : cls));
+ @Override
+ protected void onInitialize() {
+ super.onInitialize();
+ final BaseFileItem f = (BaseFileItem)getDefaultModelObject();
+ boolean editable = !treePanel.isReadOnly() && !f.isReadOnly();
+ final String selector = JQueryWidget.getSelector(this);
+ if (f.getType() == Type.Folder && editable) {
+ add(new DroppableBehavior(
+ selector
+ , new Options()
+ .set("hoverClass", Options.asString("ui-state-hover"))
+ .set("accept", Options.asString(getDefaultModelObject() instanceof Recording ? ".recorditem" : ".fileitem"))
+ , this));
}
- Component name = r.getId() == null || !editable ? new Label("name", r.getName()) : new AjaxEditableLabel<String>("name", Model.of(model.getObject().getName())) {
+ if (f.getId() != null && !treePanel.isReadOnly()) {
+ add(new DraggableBehavior(
+ selector
+ , new Options()
+ .set("revert", "treeRevert")
+ .set("cursor", Options.asString("move"))
+ .set("helper", "dragHelper")
+ .set("cursorAt", "{left: 40, top: 18}")
+ .set("containment", Options.asString(treePanel.getContainment()))
+ , this));
+ }
+ Component name = f.getId() == null || !editable ? new Label("name", f.getName()) : new AjaxEditableLabel<String>("name", Model.of(f.getName())) {
private static final long serialVersionUID = 1L;
@Override
@@ -114,18 +109,33 @@ public class FolderPanel extends Panel {
@Override
protected void onSubmit(AjaxRequestTarget target) {
super.onSubmit(target);
- BaseFileItem fi = model.getObject();
- fi.setName(getEditor().getModelObject());
- if (fi instanceof Recording) {
- recDao.update((Recording)fi);
+ f.setName(getEditor().getModelObject());
+ if (f instanceof Recording) {
+ recDao.update((Recording)f);
} else {
- fileDao.update((FileItem)fi);
+ fileDao.update((FileItem)f);
}
}
};
- drag.add(name);
- add(drop.add(drag).setOutputMarkupId(true));
- add(AttributeModifier.append(ATTR_TITLE, r.getName()));
+ add(name);
+ add(AttributeModifier.append(ATTR_TITLE, f.getName()));
+ add(styleClass);
+ add(new AjaxEventBehavior("click") {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onEvent(AjaxRequestTarget target) {
+ onClick(target, f);
+ }
+
+ @Override
+ protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
+ super.updateAjaxAttributes(attributes);
+ attributes.getDynamicExtraParameters().add(
+ String.format("return {%s: JSON.stringify({%s: attrs.event.shiftKey, %s: attrs.event.ctrlKey})};"
+ , PARAM_MOD, PARAM_SHIFT, PARAM_CTRL));
+ }
+ });
}
private void moveAll(final FileTreePanel treePanel, AjaxRequestTarget target, BaseFileItem p) {
@@ -150,4 +160,130 @@ public class FolderPanel extends Panel {
}
treePanel.updateNode(target, f);
}
+
+ private void onClick(AjaxRequestTarget target, BaseFileItem f) {
+ String mod = getRequest().getRequestParameters().getParameterValue(PARAM_MOD).toOptionalString();
+ boolean shift = false, ctrl = false;
+ if (!Strings.isEmpty(mod)) {
+ JSONObject o = new JSONObject(mod);
+ shift = o.optBoolean(PARAM_SHIFT);
+ ctrl = o.optBoolean(PARAM_CTRL);
+ }
+ treePanel.select(f, target, shift, ctrl);
+ if (Type.Folder == f.getType() && treePanel.tree.getState(f) == State.COLLAPSED) {
+ treePanel.tree.expand(f);
+ } else {
+ treePanel.update(target, f);
+ }
+ }
+
+ private CharSequence getItemStyle() {
+ final BaseFileItem f = (BaseFileItem)getDefaultModelObject();
+ boolean open = State.EXPANDED == treePanel.tree.getState(f);
+ StringBuilder style = new StringBuilder("big om-icon ");
+ if (f.getId() == null) {
+ style.append(CSS_CLASS_FILE).append(f.getHash().indexOf("my") > -1 ? "my " : "public ");
+ } else {
+ if (!f.exists()) {
+ style.append("broken ");
+ }
+ switch(f.getType()) {
+ case Folder:
+ style.append(CSS_CLASS_FILE).append(open ? "folder-open " : "folder ");
+ break;
+ case Image:
+ style.append(CSS_CLASS_FILE).append("image ");
+ break;
+ case PollChart:
+ style.append(CSS_CLASS_FILE).append("chart ");
+ break;
+ case WmlFile:
+ style.append(CSS_CLASS_FILE).append("wml ");
+ break;
+ case Video:
+ case Recording:
+ {
+ style.append("recording ");
+ if (f instanceof Recording) {
+ Status st = ((Recording)f).getStatus();
+ if (Status.RECORDING == st || Status.CONVERTING == st) {
+ style.append("processing");
+ }
+ }
+ }
+ break;
+ case Presentation:
+ style.append(CSS_CLASS_FILE).append("doc ");
+ break;
+ default:
+ break;
+ }
+ }
+ if (treePanel.isSelected(f)) {
+ style.append("ui-state-active ");
+ }
+ String cls = f instanceof Recording ? "recorditem " : "fileitem ";
+ style.append(f.isReadOnly() ? "readonlyitem " : cls);
+ return style;
+ }
+
+ @Override
+ public boolean isStopEventEnabled() {
+ return false;
+ }
+
+ @Override
+ public void onDragStart(AjaxRequestTarget target, int top, int left) {
+ // noop
+ }
+
+ @Override
+ public void onDragStop(AjaxRequestTarget target, int top, int left) {
+ // noop
+ }
+
+ @Override
+ public boolean isOverEventEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isExitEventEnabled() {
+ return false;
+ }
+
+ @Override
+ public void onOver(AjaxRequestTarget target, Component component) {
+ // noop
+ }
+
+ @Override
+ public void onExit(AjaxRequestTarget target, Component component) {
+ // noop
+ }
+
+ @Override
+ public void onDrop(AjaxRequestTarget target, Component component) {
+ Object o = component.getDefaultModelObject();
+ if (o instanceof BaseFileItem) {
+ BaseFileItem p = (BaseFileItem)getDefaultModelObject();
+ BaseFileItem f = (BaseFileItem)o;
+ if (treePanel.isSelected(f)) {
+ moveAll(treePanel, target, p);
+ } else {
+ move(treePanel, target, p, f);
+ }
+ treePanel.updateNode(target, p);
+ }
+ target.add(treePanel.trees);
+ }
+
+ private class StyleBehavior extends Behavior {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onComponentTag(Component component, ComponentTag tag) {
+ tag.put(ATTR_CLASS, getItemStyle());
+ }
+ }
}
diff --git a/openmeetings-web/src/main/webapp/css/raw-tree.css b/openmeetings-web/src/main/webapp/css/raw-tree.css
index beb2b1b..220c174 100644
--- a/openmeetings-web/src/main/webapp/css/raw-tree.css
+++ b/openmeetings-web/src/main/webapp/css/raw-tree.css
@@ -47,10 +47,11 @@
padding-right: 5px;
padding-left: 5px;
}
-.trees a.om-icon {
+.trees .om-icon {
width: auto;
+ margin-top: 0;
}
-.trees a.om-icon span {
+.trees .om-icon span {
white-space: nowrap;
padding-right: 20px;
vertical-align: top;