SideBySide2: Display icon during selection to insert comment

Since double click doesn't work on CodeMirror but range selection
does, display a small comment box icon above and to the right of the
end of the selection region.  Clicking this icon will create a new
draft comment on the region.

Change-Id: Id0533b698952d707b720b37fb405e78f1e54e7a8
This commit is contained in:
Shawn Pearce
2013-12-13 08:32:09 -08:00
parent de65050e5d
commit f146cf57b2
6 changed files with 112 additions and 2 deletions

View File

@@ -37,6 +37,7 @@ class DiffTable extends Composite {
private static final Binder uiBinder = GWT.create(Binder.class);
interface DiffTableStyle extends CssResource {
String insertCommentIcon();
String fullscreen();
String intralineBg();
String diff();

View File

@@ -23,6 +23,11 @@ limitations under the License.
@external .cm-keymap-fat-cursor, CodeMirror-cursor;
@external .cm-searching, .cm-trailingspace, .cm-tab;
.insertCommentIcon {
cursor: pointer;
position: absolute;
z-index: 150;
}
.fullscreen {
background-color: #f7f7f7;
border-bottom: 1px solid #ddd;

View File

@@ -54,7 +54,10 @@ import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.logical.shared.ResizeEvent;
@@ -65,6 +68,7 @@ import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.globalkey.client.GlobalKey;
@@ -73,6 +77,7 @@ import com.google.gwtexpui.globalkey.client.KeyCommandSet;
import com.google.gwtexpui.globalkey.client.ShowHelpCommand;
import net.codemirror.lib.CodeMirror;
import net.codemirror.lib.CodeMirror.BeforeSelectionChangeHandler;
import net.codemirror.lib.CodeMirror.GutterClickHandler;
import net.codemirror.lib.CodeMirror.LineClassWhere;
import net.codemirror.lib.CodeMirror.LineHandle;
@@ -83,6 +88,7 @@ import net.codemirror.lib.KeyMap;
import net.codemirror.lib.LineCharacter;
import net.codemirror.lib.LineWidget;
import net.codemirror.lib.ModeInjector;
import net.codemirror.lib.Rect;
import net.codemirror.lib.TextMarker;
import net.codemirror.lib.TextMarker.FromTo;
@@ -314,6 +320,7 @@ public class SideBySide2 extends Screen {
}
private void registerCmEvents(final CodeMirror cm) {
cm.on("beforeSelectionChange", onSelectionChange(cm));
cm.on("cursorActivity", updateActiveLine(cm));
cm.on("gutterClick", onGutterClick(cm));
cm.on("renderLine", resizeLinePadding(getSideFromCm(cm)));
@@ -399,6 +406,47 @@ public class SideBySide2 extends Screen {
.on("Shift-Right", flipCursorSide(cm, false)));
}
private BeforeSelectionChangeHandler onSelectionChange(final CodeMirror cm) {
return new BeforeSelectionChangeHandler() {
private Image icon;
@Override
public void handle(CodeMirror cm, LineCharacter anchor, LineCharacter head) {
if (anchor == head
|| (anchor.getLine() == head.getLine()
&& anchor.getCh() == head.getCh())) {
if (icon != null) {
icon.setVisible(false);
}
return;
} else if (icon == null) {
init(anchor);
}
icon.setVisible(true);
Rect r = cm.charCoords(head, "local");
Style s = icon.getElement().getStyle();
s.setTop((int) (r.top() - icon.getOffsetHeight() + 2), Unit.PX);
s.setLeft((int) (r.right() - icon.getOffsetWidth() / 2), Unit.PX);
}
private void init(LineCharacter anchor) {
icon = new Image(Gerrit.RESOURCES.draftComments());
icon.setTitle(PatchUtil.C.commentInsert());
icon.setStyleName(DiffTable.style.insertCommentIcon());
icon.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
icon.setVisible(false);
insertNewDraft(cm).run();
}
});
add(icon);
cm.addWidget(anchor, icon.getElement(), false);
}
};
}
@Override
public void registerKeys() {
super.registerKeys();

View File

@@ -133,6 +133,7 @@ class SkipBar extends Composite {
void expandAll() {
clearMarkerAndWidget();
removeFromParent();
updateSelection();
}
private void expandBefore() {
@@ -148,6 +149,7 @@ class SkipBar extends Composite {
.set("noHScroll", true);
setWidget(cm.addLineWidget(newStart - 1, getElement(), config));
updateSkipNum();
updateSelection();
}
private void expandAfter() {
@@ -167,6 +169,14 @@ class SkipBar extends Composite {
setWidget(cm.addLineWidget(newEnd + 1, getElement(), config));
}
updateSkipNum();
updateSelection();
}
private void updateSelection() {
if (cm.somethingSelected()) {
FromTo sel = cm.getSelectedRange();
cm.setSelection(sel.getFrom(), sel.getTo());
}
}
@UiHandler("skipNum")

View File

@@ -138,6 +138,10 @@ public class CodeMirror extends JavaScriptObject {
return this.heightAtLine(line, mode);
}-*/;
public final native Rect charCoords(LineCharacter pos, String mode) /*-{
return this.charCoords(pos, mode);
}-*/;
public final native CodeMirrorDoc getDoc() /*-{
return this.getDoc();
}-*/;
@@ -197,6 +201,12 @@ public class CodeMirror extends JavaScriptObject {
}));
}-*/;
public final native void on(String event, BeforeSelectionChangeHandler handler) /*-{
this.on(event, $entry(function(cm, e) {
handler.@net.codemirror.lib.CodeMirror.BeforeSelectionChangeHandler::handle(Lnet/codemirror/lib/CodeMirror;Lnet/codemirror/lib/LineCharacter;Lnet/codemirror/lib/LineCharacter;)(cm,e.anchor,e.head);
}));
}-*/;
public final native LineCharacter getCursor() /*-{
return this.getCursor();
}-*/;
@@ -209,8 +219,12 @@ public class CodeMirror extends JavaScriptObject {
return FromTo.create(getCursor("start"), getCursor("end"));
}
public final native void setSelection(LineCharacter lineCh) /*-{
this.setSelection(lineCh);
public final native void setSelection(LineCharacter anchor) /*-{
this.setSelection(anchor);
}-*/;
public final native void setSelection(LineCharacter anchor, LineCharacter head) /*-{
this.setSelection(anchor, head);
}-*/;
public final native void setCursor(LineCharacter lineCh) /*-{
@@ -345,4 +359,8 @@ public class CodeMirror extends JavaScriptObject {
public void handle(CodeMirror instance, int line, String gutter,
NativeEvent clickEvent);
}
public interface BeforeSelectionChangeHandler {
public void handle(CodeMirror instance, LineCharacter anchor, LineCharacter head);
}
}

View File

@@ -0,0 +1,28 @@
// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package net.codemirror.lib;
import com.google.gwt.core.client.JavaScriptObject;
/** {left, right, top, bottom} objects used within CodeMirror. */
public class Rect extends JavaScriptObject {
public final native double left() /*-{ return this.left }-*/;
public final native double right() /*-{ return this.right }-*/;
public final native double top() /*-{ return this.top }-*/;
public final native double bottom() /*-{ return this.bottom }-*/;
protected Rect() {
}
}