Enable buttons on CommentBox.

Add click handlers to buttons for making REST API calls.

Fixed bugs in CommentApi. The callbacks were parameterized with
incorrect types.

Change-Id: If1f7ccee37c68434fdf29df63ad904453322139b
This commit is contained in:
Michael Zhou
2013-06-24 11:30:16 -07:00
parent 41d9278253
commit 19c8230231
11 changed files with 476 additions and 124 deletions

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.client.changes;
import com.google.gerrit.client.rpc.NativeMap; import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.RestApi; import com.google.gerrit.client.rpc.RestApi;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArray;
import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -28,7 +29,7 @@ public class CommentApi {
} }
public static void comment(PatchSet.Id id, String commentId, public static void comment(PatchSet.Id id, String commentId,
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) { AsyncCallback<CommentInfo> cb) {
revision(id, "comments").id(commentId).get(cb); revision(id, "comments").id(commentId).get(cb);
} }
@@ -38,22 +39,22 @@ public class CommentApi {
} }
public static void draft(PatchSet.Id id, String draftId, public static void draft(PatchSet.Id id, String draftId,
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) { AsyncCallback<CommentInfo> cb) {
revision(id, "drafts").id(draftId).get(cb); revision(id, "drafts").id(draftId).get(cb);
} }
public static void createDraft(PatchSet.Id id, CommentInfo content, public static void createDraft(PatchSet.Id id, CommentInput content,
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) { AsyncCallback<CommentInfo> cb) {
revision(id, "drafts").put(content, cb); revision(id, "drafts").put(content, cb);
} }
public static void updateDraft(PatchSet.Id id, String draftId, public static void updateDraft(PatchSet.Id id, String draftId,
CommentInfo content, AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) { CommentInput content, AsyncCallback<CommentInfo> cb) {
revision(id, "drafts").id(draftId).put(content, cb); revision(id, "drafts").id(draftId).put(content, cb);
} }
public static void deleteDraft(PatchSet.Id id, String draftId, public static void deleteDraft(PatchSet.Id id, String draftId,
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) { AsyncCallback<JavaScriptObject> cb) {
revision(id, "drafts").id(draftId).delete(cb); revision(id, "drafts").id(draftId).delete(cb);
} }

View File

@@ -22,6 +22,32 @@ import com.google.gwtjsonrpc.client.impl.ser.JavaSqlTimestamp_JsonSerializer;
import java.sql.Timestamp; import java.sql.Timestamp;
public class CommentInfo extends JavaScriptObject { public class CommentInfo extends JavaScriptObject {
public static CommentInfo create(String path, Side side, int line,
String in_reply_to, String message) {
CommentInfo info = createObject().cast();
info.setPath(path);
info.setSide(side);
info.setLine(line);
info.setInReplyTo(in_reply_to);
info.setMessage(message);
return info;
}
private final native void setId(String id) /*-{ this.id = id; }-*/;
private final native void setPath(String path) /*-{ this.path = path; }-*/;
private final void setSide(Side side) {
setSideRaw(side.toString());
}
private final native void setSideRaw(String side) /*-{ this.side = side; }-*/;
private final native void setLine(int line) /*-{ this.line = line; }-*/;
private final native void setInReplyTo(String in_reply_to) /*-{
this.in_reply_to = in_reply_to;
}-*/;
private final native void setMessage(String message) /*-{ this.message = message; }-*/;
public final native String id() /*-{ return this.id; }-*/; public final native String id() /*-{ return this.id; }-*/;
public final native String path() /*-{ return this.path; }-*/; public final native String path() /*-{ return this.path; }-*/;
@@ -39,7 +65,10 @@ public class CommentInfo extends JavaScriptObject {
public final native String message() /*-{ return this.message; }-*/; public final native String message() /*-{ return this.message; }-*/;
public final Timestamp updated() { public final Timestamp updated() {
return JavaSqlTimestamp_JsonSerializer.parseTimestamp(updatedRaw()); String updatedRaw = updatedRaw();
return updatedRaw == null
? null
: JavaSqlTimestamp_JsonSerializer.parseTimestamp(updatedRaw());
} }
private final native String updatedRaw() /*-{ return this.updated; }-*/; private final native String updatedRaw() /*-{ return this.updated; }-*/;

View File

@@ -0,0 +1,76 @@
// 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 com.google.gerrit.client.changes;
import com.google.gerrit.common.changes.Side;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwtjsonrpc.client.impl.ser.JavaSqlTimestamp_JsonSerializer;
import java.sql.Timestamp;
public class CommentInput extends JavaScriptObject {
public static CommentInput create(CommentInfo original) {
CommentInput input = createObject().cast();
input.setId(original.id());
input.setPath(original.path());
input.setSide(original.side());
if (original.has_line()) {
input.setLine(original.line());
}
input.setInReplyTo(original.in_reply_to());
input.setMessage(original.message());
return input;
}
public final native void setId(String id) /*-{ this.id = id; }-*/;
public final native void setPath(String path) /*-{ this.path = path; }-*/;
public final void setSide(Side side) {
setSideRaw(side.toString());
}
private final native void setSideRaw(String side) /*-{ this.side = side; }-*/;
public final native void setLine(int line) /*-{ this.line = line; }-*/;
public final native void setInReplyTo(String in_reply_to) /*-{
this.in_reply_to = in_reply_to;
}-*/;
public final native void setMessage(String message) /*-{ this.message = message; }-*/;
public final native String id() /*-{ return this.id; }-*/;
public final native String path() /*-{ return this.path; }-*/;
public final Side side() {
String s = sideRaw();
return s != null
? Side.valueOf(s)
: Side.REVISION;
}
private final native String sideRaw() /*-{ return this.side }-*/;
public final native int line() /*-{ return this.line; }-*/;
public final native String in_reply_to() /*-{ return this.in_reply_to; }-*/;
public final native String message() /*-{ return this.message; }-*/;
public final Timestamp updated() {
return JavaSqlTimestamp_JsonSerializer.parseTimestamp(updatedRaw());
}
private final native String updatedRaw() /*-{ return this.updated; }-*/;
public final native boolean has_line() /*-{ return this.hasOwnProperty('line'); }-*/;
protected CommentInput() {
}
}

View File

@@ -48,15 +48,21 @@ import net.codemirror.lib.CodeMirror;
import net.codemirror.lib.CodeMirror.LineClassWhere; import net.codemirror.lib.CodeMirror.LineClassWhere;
import net.codemirror.lib.Configuration; import net.codemirror.lib.Configuration;
import net.codemirror.lib.LineCharacter; import net.codemirror.lib.LineCharacter;
import net.codemirror.lib.LineWidget;
import net.codemirror.lib.ModeInjector; import net.codemirror.lib.ModeInjector;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
public class CodeMirrorDemo extends Screen { public class CodeMirrorDemo extends Screen {
private static final int HEADER_FOOTER = 60 + 15 * 2 + 38; private static final int HEADER_FOOTER = 60 + 15 * 2 + 38;
private static final JsArrayString EMPTY = private static final JsArrayString EMPTY =
JavaScriptObject.createArray().cast(); JavaScriptObject.createArray().cast();
private static final Configuration COMMENT_BOX_CONFIG =
Configuration.create().set("coverGutter", true);
private final PatchSet.Id base; private final PatchSet.Id base;
private final PatchSet.Id revision; private final PatchSet.Id revision;
private final String path; private final String path;
@@ -67,10 +73,11 @@ public class CodeMirrorDemo extends Screen {
private HandlerRegistration resizeHandler; private HandlerRegistration resizeHandler;
private JsArray<CommentInfo> published; private JsArray<CommentInfo> published;
private JsArray<CommentInfo> drafts; private JsArray<CommentInfo> drafts;
private List<Runnable> resizeCallbacks; private List<CommentBox> initialBoxes;
private DiffInfo diff; private DiffInfo diff;
private LineMapper mapper; private LineMapper mapper;
private CommentLinkProcessor commentLinkProcessor; private CommentLinkProcessor commentLinkProcessor;
private Map<String, PublishedBox> publishedMap;
public CodeMirrorDemo( public CodeMirrorDemo(
PatchSet.Id base, PatchSet.Id base,
@@ -123,7 +130,7 @@ public class CodeMirrorDemo extends Screen {
@Override @Override
public void onSuccess(NativeMap<JsArray<CommentInfo>> m) { drafts = m.get(path); } public void onSuccess(NativeMap<JsArray<CommentInfo>> m) { drafts = m.get(path); }
})); }));
ChangeApi.detail(revision.getParentKey().get(), new GerritCallback<ChangeInfo>(){ ChangeApi.detail(revision.getParentKey().get(), new GerritCallback<ChangeInfo>() {
@Override @Override
public void onSuccess(ChangeInfo result) { public void onSuccess(ChangeInfo result) {
Project.NameKey project = result.project_name_key(); Project.NameKey project = result.project_name_key();
@@ -156,10 +163,9 @@ public class CodeMirrorDemo extends Screen {
Scheduler.get().scheduleDeferred(new ScheduledCommand() { Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override @Override
public void execute() { public void execute() {
for (Runnable r : resizeCallbacks) { for (CommentBox box : initialBoxes) {
r.run(); box.resizePaddingWidget();
} }
resizeCallbacks = null;
} }
}); });
} }
@@ -167,6 +173,7 @@ public class CodeMirrorDemo extends Screen {
@Override @Override
protected void onUnload() { protected void onUnload() {
super.onUnload(); super.onUnload();
if (resizeHandler != null) { if (resizeHandler != null) {
resizeHandler.removeHandler(); resizeHandler.removeHandler();
resizeHandler = null; resizeHandler = null;
@@ -180,18 +187,21 @@ public class CodeMirrorDemo extends Screen {
cmB = null; cmB = null;
} }
Window.enableScrolling(true); Window.enableScrolling(true);
mapper = null;
initialBoxes = null;
publishedMap = null;
} }
private void display(DiffInfo diffInfo) { private void display(DiffInfo diffInfo) {
cmA = displaySide(diffInfo.meta_a(), diffInfo.text_a(), diffTable.getCmA()); cmA = displaySide(diffInfo.meta_a(), diffInfo.text_a(), diffTable.getCmA());
cmB = displaySide(diffInfo.meta_b(), diffInfo.text_b(), diffTable.getCmB()); cmB = displaySide(diffInfo.meta_b(), diffInfo.text_b(), diffTable.getCmB());
render(diffInfo); render(diffInfo);
resizeCallbacks = new ArrayList<Runnable>(); initialBoxes = new ArrayList<CommentBox>();
renderComments(published, false); publishedMap = new HashMap<String, PublishedBox>(published.length());
renderComments(drafts, true); renderPublished();
renderDrafts();
published = null; published = null;
drafts = null; drafts = null;
mapper = null;
// TODO: Probably need horizontal resize // TODO: Probably need horizontal resize
resizeHandler = Window.addResizeHandler(new ResizeHandler() { resizeHandler = Window.addResizeHandler(new ResizeHandler() {
@@ -261,35 +271,59 @@ public class CodeMirrorDemo extends Screen {
} }
} }
private void renderComments(JsArray<CommentInfo> comments, boolean isDraft) { DraftBox addReplyBox(CommentInfo replyTo, String initMessage, boolean doSave) {
Configuration config = Configuration.create().set("coverGutter", true); CommentInfo info = CommentInfo.create(
for (int i = 0; comments != null && i < comments.length(); i++) { path,
CommentInfo info = comments.get(i); replyTo.side(),
Side mySide = info.side(); replyTo.line(),
CodeMirror cm = mySide == Side.PARENT ? cmA : cmB; replyTo.id(),
CodeMirror other = otherCM(cm); initMessage);
final CommentBox box = isDraft ? DraftBox box = new DraftBox(this, revision, info, commentLinkProcessor,
new DraftBox(info.author(), info.updated(), info.message(), true, !doSave);
commentLinkProcessor) : addCommentBox(info, box);
new PublishedBox(info.author(), info.updated(), info.message(), return box;
commentLinkProcessor); }
int line = info.line() - 1; // CommentInfo is 1-based, but CM is 0-based
diffTable.add(box); CommentBox addCommentBox(CommentInfo info, final CommentBox box) {
cm.addLineWidget(line, box.getElement(), config); diffTable.add(box);
int lineToPad = mapper.lineOnOther(mySide, line); Side mySide = info.side();
// Estimated height at 21px, fixed by deferring after display CodeMirror cm = mySide == Side.PARENT ? cmA : cmB;
final Element paddingOtherside = addPaddingWidget(other, CodeMirror other = otherCM(cm);
diffTable.style.padding(), lineToPad, int line = info.line() - 1; // CommentInfo is 1-based, but CM is 0-based
21, Unit.PX); LineWidget boxWidget =
Runnable callback = new Runnable() { cm.addLineWidget(line, box.getElement(), COMMENT_BOX_CONFIG);
@Override int lineToPad = mapper.lineOnOther(mySide, line);
public void run() { // Estimated height at 21px, fixed by deferring after display
paddingOtherside.getStyle().setHeight( LineWidgetElementPair padding = addPaddingWidget(
box.getOffsetHeight(), Unit.PX); other, diffTable.style.padding(), lineToPad, 21, Unit.PX);
} box.setSelfWidget(boxWidget);
}; box.setPadding(padding.widget, padding.element);
resizeCallbacks.add(callback); return box;
box.setOpenCloseHandler(callback); }
private void renderPublished() {
for (int i = 0; published != null && i < published.length(); i++) {
CommentInfo info = published.get(i);
final PublishedBox box =
new PublishedBox(this, revision, info, commentLinkProcessor);
addCommentBox(info, box);
initialBoxes.add(box);
publishedMap.put(info.id(), box);
}
}
private void renderDrafts() {
for (int i = 0; drafts != null && i < drafts.length(); i++) {
CommentInfo info = drafts.get(i);
final DraftBox box =
new DraftBox(this, revision, info, commentLinkProcessor, false, false);
addCommentBox(info, box);
initialBoxes.add(box);
PublishedBox replyToBox = publishedMap.get(info.in_reply_to());
if (replyToBox != null) {
replyToBox.registerReplyBox(box);
box.registerReplyToBox(replyToBox);
}
} }
} }
@@ -341,16 +375,16 @@ public class CodeMirrorDemo extends Screen {
cnt, Unit.EM); cnt, Unit.EM);
} }
private Element addPaddingWidget(CodeMirror cm, String style, int line, private LineWidgetElementPair addPaddingWidget(CodeMirror cm, String style,
int height, Unit unit) { int line, int height, Unit unit) {
Element div = DOM.createDiv(); Element div = DOM.createDiv();
div.setClassName(style); div.setClassName(style);
div.getStyle().setHeight(height, unit); div.getStyle().setHeight(height, unit);
Configuration config = Configuration.create() Configuration config = Configuration.create()
.set("coverGutter", true) .set("coverGutter", true)
.set("above", line == -1); .set("above", line == -1);
cm.addLineWidget(line == -1 ? 0 : line, div, config); LineWidget widget = cm.addLineWidget(line == -1 ? 0 : line, div, config);
return div; return new LineWidgetElementPair(widget, div);
} }
private Runnable doScroll(final CodeMirror cm) { private Runnable doScroll(final CodeMirror cm) {
@@ -368,6 +402,16 @@ public class CodeMirrorDemo extends Screen {
: null; : null;
} }
private static class LineWidgetElementPair {
private LineWidget widget;
private Element element;
private LineWidgetElementPair(LineWidget w, Element e) {
widget = w;
element = e;
}
}
static class EditIterator { static class EditIterator {
private final JsArrayString lines; private final JsArrayString lines;
private final int startLine; private final int startLine;

View File

@@ -14,8 +14,11 @@
package com.google.gerrit.client.diff; package com.google.gerrit.client.diff;
import com.google.gerrit.client.account.AccountInfo; import com.google.gerrit.client.changes.CommentInfo;
import com.google.gerrit.client.ui.CommentLinkProcessor; import com.google.gerrit.client.ui.CommentLinkProcessor;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.HandlerRegistration;
@@ -28,6 +31,8 @@ import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.safehtml.client.SafeHtml; import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
import net.codemirror.lib.LineWidget;
import java.sql.Timestamp; import java.sql.Timestamp;
/** An HtmlPanel for displaying a comment */ /** An HtmlPanel for displaying a comment */
@@ -39,7 +44,12 @@ abstract class CommentBox extends Composite {
private CommentLinkProcessor commentLinkProcessor; private CommentLinkProcessor commentLinkProcessor;
private HandlerRegistration headerClick; private HandlerRegistration headerClick;
private Runnable clickCallback; private CommentInfo original;
private PatchSet.Id patchSetId;
private LineWidget selfWidget;
private LineWidget paddingWidget;
private Element paddingWidgetEle;
private CodeMirrorDemo diffView;
@UiField(provided=true) @UiField(provided=true)
CommentBoxHeader header; CommentBoxHeader header;
@@ -50,13 +60,18 @@ abstract class CommentBox extends Composite {
@UiField @UiField
CommentBoxResources res; CommentBoxResources res;
protected CommentBox(UiBinder<? extends Widget, CommentBox> binder, protected CommentBox(
AccountInfo author, Timestamp when, String message, CodeMirrorDemo host,
CommentLinkProcessor linkProcessor, boolean isDraft) { UiBinder<? extends Widget, CommentBox> binder,
PatchSet.Id id, CommentInfo info, CommentLinkProcessor linkProcessor,
boolean isDraft) {
diffView = host;
commentLinkProcessor = linkProcessor; commentLinkProcessor = linkProcessor;
header = new CommentBoxHeader(author, when, isDraft); original = info;
patchSetId = id;
header = new CommentBoxHeader(info.author(), info.updated(), isDraft);
initWidget(binder.createAndBindUi(this)); initWidget(binder.createAndBindUi(this));
setMessageText(message); setMessageText(info.message());
setOpen(false); setOpen(false);
} }
@@ -68,24 +83,12 @@ abstract class CommentBox extends Composite {
@Override @Override
public void onClick(ClickEvent event) { public void onClick(ClickEvent event) {
setOpen(!isOpen()); setOpen(!isOpen());
if (clickCallback != null) { resizePaddingWidget();
clickCallback.run();
}
} }
}, ClickEvent.getType()); }, ClickEvent.getType());
res.style().ensureInjected(); res.style().ensureInjected();
} }
void setOpenCloseHandler(final Runnable callback) {
clickCallback = callback;
}
protected void runClickCallback() {
if (clickCallback != null) {
clickCallback.run();
}
}
@Override @Override
protected void onUnload() { protected void onUnload() {
super.onUnload(); super.onUnload();
@@ -96,7 +99,20 @@ abstract class CommentBox extends Composite {
} }
} }
private void setMessageText(String message) { void setSelfWidget(LineWidget widget) {
selfWidget = widget;
}
void setPadding(LineWidget widget, Element element) {
paddingWidget = widget;
paddingWidgetEle = element;
}
void resizePaddingWidget() {
paddingWidgetEle.getStyle().setHeight(getOffsetHeight(), Unit.PX);
}
protected void setMessageText(String message) {
if (message == null) { if (message == null) {
message = ""; message = "";
} else { } else {
@@ -108,7 +124,11 @@ abstract class CommentBox extends Composite {
SafeHtml.set(contentPanelMessage, buf); SafeHtml.set(contentPanelMessage, buf);
} }
private void setOpen(boolean open) { protected void setDate(Timestamp when) {
header.setDate(when);
}
protected void setOpen(boolean open) {
if (open) { if (open) {
removeStyleName(res.style().close()); removeStyleName(res.style().close());
addStyleName(res.style().open()); addStyleName(res.style().open());
@@ -121,4 +141,28 @@ abstract class CommentBox extends Composite {
private boolean isOpen() { private boolean isOpen() {
return getStyleName().contains(res.style().open()); return getStyleName().contains(res.style().open());
} }
protected CodeMirrorDemo getDiffView() {
return diffView;
}
protected PatchSet.Id getPatchSetId() {
return patchSetId;
}
protected CommentInfo getOriginal() {
return original;
}
protected LineWidget getSelfWidget() {
return selfWidget;
}
protected LineWidget getPaddingWidget() {
return paddingWidget;
}
protected void updateOriginal(CommentInfo newInfo) {
original = newInfo;
}
} }

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.client.diff;
import com.google.gerrit.client.AvatarImage; import com.google.gerrit.client.AvatarImage;
import com.google.gerrit.client.FormatUtil; import com.google.gerrit.client.FormatUtil;
import com.google.gerrit.client.account.AccountInfo; import com.google.gerrit.client.account.AccountInfo;
import com.google.gerrit.client.patches.PatchUtil;
import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Element;
import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiBinder;
@@ -35,6 +36,8 @@ class CommentBoxHeader extends Composite {
interface Binder extends UiBinder<HTMLPanel, CommentBoxHeader> {} interface Binder extends UiBinder<HTMLPanel, CommentBoxHeader> {}
private static Binder uiBinder = GWT.create(Binder.class); private static Binder uiBinder = GWT.create(Binder.class);
private boolean isDraft;
@UiField(provided=true) @UiField(provided=true)
AvatarImage avatar; AvatarImage avatar;
@@ -51,13 +54,22 @@ class CommentBoxHeader extends Composite {
// TODO: Set avatar's display to none if we get a 404. // TODO: Set avatar's display to none if we get a 404.
avatar = new AvatarImage(author, 26); avatar = new AvatarImage(author, 26);
initWidget(uiBinder.createAndBindUi(this)); initWidget(uiBinder.createAndBindUi(this));
String dateText = FormatUtil.shortFormatDayTime(when); this.isDraft = isDraft;
if (when != null) {
setDate(when);
}
if (isDraft) { if (isDraft) {
name.setInnerText("(Draft)"); name.setInnerText("(Draft)");
date.setInnerText("Draft saved at " + dateText);
} else { } else {
name.setInnerText(FormatUtil.name(author)); name.setInnerText(FormatUtil.name(author));
date.setInnerText(dateText); }
}
void setDate(Timestamp when) {
if (isDraft) {
date.setInnerText(PatchUtil.M.draftSaved(when));
} else {
date.setInnerText(FormatUtil.shortFormatDayTime(when));
} }
} }

View File

@@ -14,22 +14,29 @@
package com.google.gerrit.client.diff; package com.google.gerrit.client.diff;
import com.google.gerrit.client.account.AccountInfo; import com.google.gerrit.client.changes.CommentApi;
import com.google.gerrit.client.changes.CommentInfo;
import com.google.gerrit.client.changes.CommentInput;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.CommentLinkProcessor; import com.google.gerrit.client.ui.CommentLinkProcessor;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.DoubleClickEvent; import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler; import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.resources.client.CssResource; import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwtexpui.globalkey.client.NpTextArea; import com.google.gwtexpui.globalkey.client.NpTextArea;
import java.sql.Timestamp;
/** An HtmlPanel for displaying and editing a draft */ /** An HtmlPanel for displaying and editing a draft */
//TODO: Make the buttons functional.
class DraftBox extends CommentBox { class DraftBox extends CommentBox {
interface Binder extends UiBinder<HTMLPanel, DraftBox> {} interface Binder extends UiBinder<HTMLPanel, DraftBox> {}
private static UiBinder<HTMLPanel, CommentBox> uiBinder = private static UiBinder<HTMLPanel, CommentBox> uiBinder =
@@ -38,6 +45,7 @@ class DraftBox extends CommentBox {
interface DraftBoxStyle extends CssResource { interface DraftBoxStyle extends CssResource {
String edit(); String edit();
String view(); String view();
String newDraft();
} }
@UiField @UiField
@@ -46,51 +54,149 @@ class DraftBox extends CommentBox {
@UiField @UiField
DraftBoxStyle draftStyle; DraftBoxStyle draftStyle;
@UiField
Button edit;
@UiField
Button save;
@UiField
Button cancel;
@UiField
Button discard;
private HandlerRegistration messageClick; private HandlerRegistration messageClick;
private boolean isNew;
private PublishedBox replyToBox;
DraftBox(AccountInfo author, Timestamp when, String message, DraftBox(
CommentLinkProcessor linkProcessor) { CodeMirrorDemo host,
super(uiBinder, author, when, message, linkProcessor, true); PatchSet.Id id,
CommentInfo info,
CommentLinkProcessor linkProcessor,
boolean isNew,
boolean saveOnInit) {
super(host, uiBinder, id, info, linkProcessor, true);
setEdit(false); this.isNew = isNew;
// TODO: Need a resize handler on editArea. editArea.setText(contentPanelMessage.getText());
setEdit(isNew && !saveOnInit);
setOpen(isNew && !saveOnInit);
if (saveOnInit) {
onSave(null);
}
if (isNew) {
addStyleName(draftStyle.newDraft());
}
} }
@Override @Override
protected void onLoad() { protected void onLoad() {
super.onLoad(); super.onLoad();
messageClick = contentPanelMessage.addDomHandler(new DoubleClickHandler() { messageClick = contentPanelMessage.addDoubleClickHandler(
new DoubleClickHandler() {
@Override @Override
public void onDoubleClick(DoubleClickEvent arg0) { public void onDoubleClick(DoubleClickEvent arg0) {
editArea.setText(contentPanelMessage.getText()); setEdit(true);
setEdit(!isEdit());
runClickCallback();
} }
}, DoubleClickEvent.getType()); });
} addDomHandler(new MouseMoveHandler() {
@Override
private void setEdit(boolean edit) { public void onMouseMove(MouseMoveEvent arg0) {
if (edit) { resizePaddingWidget();
removeStyleName(draftStyle.view()); }
addStyleName(draftStyle.edit()); }, MouseMoveEvent.getType());
} else {
removeStyleName(draftStyle.edit());
addStyleName(draftStyle.view());
}
}
private boolean isEdit() {
return getStyleName().contains(draftStyle.edit());
} }
@Override @Override
protected void onUnload() { protected void onUnload() {
super.onUnload(); super.onUnload();
if (messageClick != null) { messageClick.removeHandler();
messageClick.removeHandler(); messageClick = null;
messageClick = null; }
void setEdit(boolean edit) {
if (edit) {
removeStyleName(draftStyle.view());
addStyleName(draftStyle.edit());
editArea.setText(contentPanelMessage.getText());
editArea.setFocus(true);
} else {
removeStyleName(draftStyle.edit());
addStyleName(draftStyle.view());
}
resizePaddingWidget();
}
void registerReplyToBox(PublishedBox box) {
replyToBox = box;
}
private void removeUI() {
if (replyToBox != null) {
replyToBox.unregisterReplyBox();
}
getPaddingWidget().clear();
removeFromParent();
getSelfWidget().clear();
}
@UiHandler("edit")
void onEdit(ClickEvent e) {
setEdit(true);
}
@UiHandler("save")
void onSave(ClickEvent e) {
final String message = editArea.getText();
if (message.equals("")) {
return;
}
CommentInfo original = getOriginal();
CommentInput input = CommentInput.create(original);
input.setMessage(message);
GerritCallback<CommentInfo> cb = new GerritCallback<CommentInfo>() {
@Override
public void onSuccess(CommentInfo result) {
updateOriginal(result);
setEdit(false);
setMessageText(message);
setDate(result.updated());
resizePaddingWidget();
if (isNew) {
removeStyleName(draftStyle.newDraft());
isNew = false;
}
}
};
if (isNew) {
CommentApi.createDraft(getPatchSetId(), input, cb);
} else {
CommentApi.updateDraft(getPatchSetId(), original.id(), input, cb);
}
}
@UiHandler("cancel")
void onCancel(ClickEvent e) {
setEdit(false);
resizePaddingWidget();
}
@UiHandler("discard")
void onDiscard(ClickEvent e) {
if (isNew) {
removeUI();
} else {
CommentApi.deleteDraft(getPatchSetId(), getOriginal().id(),
new GerritCallback<JavaScriptObject>() {
@Override
public void onSuccess(JavaScriptObject result) {
removeUI();
}
});
} }
} }
} }

View File

@@ -26,29 +26,33 @@ limitations under the License.
.view .editArea { .view .editArea {
display: none; display: none;
} }
.newDraft .cancel {
display: none;
}
</ui:style> </ui:style>
<g:HTMLPanel styleName='{res.style.commentBox}'> <g:HTMLPanel styleName='{res.style.commentBox}'>
<d:CommentBoxHeader ui:field='header' /> <d:CommentBoxHeader ui:field='header' />
<div class='{res.style.contentPanel}'> <div class='{res.style.contentPanel}'>
<c:NpTextArea ui:field='editArea' styleName='{draftStyle.editArea}'/> <c:NpTextArea ui:field='editArea' styleName='{draftStyle.editArea}'/>
<div> <div>
<button ui:field='save' class='{draftStyle.editArea}'> <g:Button ui:field='save' styleName='{draftStyle.editArea}'>
<ui:msg>Save</ui:msg> <ui:msg>Save</ui:msg>
</button> </g:Button>
<button ui:field='cancel' class='{draftStyle.editArea}'> <g:Button ui:field='cancel'
styleName='{draftStyle.editArea} {draftStyle.cancel}'>
<ui:msg>Cancel</ui:msg> <ui:msg>Cancel</ui:msg>
</button> </g:Button>
<button ui:field='discard' class='{draftStyle.editArea}'> <g:Button ui:field='discard' styleName='{draftStyle.editArea}'>
<ui:msg>Discard</ui:msg> <ui:msg>Discard</ui:msg>
</button> </g:Button>
</div> </div>
</div> </div>
<div class='{res.style.contentPanel}'> <div class='{res.style.contentPanel}'>
<g:HTML ui:field='contentPanelMessage' <g:HTML ui:field='contentPanelMessage'
styleName='{res.style.message} {draftStyle.messagePanel}'></g:HTML> styleName='{res.style.message} {draftStyle.messagePanel}'></g:HTML>
<button ui:field='edit' class='{draftStyle.messagePanel}'> <g:Button ui:field='edit' styleName='{draftStyle.messagePanel}'>
<ui:msg>Edit</ui:msg> <ui:msg>Edit</ui:msg>
</button> </g:Button>
</div> </div>
</g:HTMLPanel> </g:HTMLPanel>
</ui:UiBinder> </ui:UiBinder>

View File

@@ -14,23 +14,59 @@
package com.google.gerrit.client.diff; package com.google.gerrit.client.diff;
import com.google.gerrit.client.account.AccountInfo; import com.google.gerrit.client.changes.CommentInfo;
import com.google.gerrit.client.ui.CommentLinkProcessor; import com.google.gerrit.client.ui.CommentLinkProcessor;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.HTMLPanel;
import java.sql.Timestamp;
/** An HtmlPanel for displaying a published comment */ /** An HtmlPanel for displaying a published comment */
// TODO: Make the buttons functional.
class PublishedBox extends CommentBox { class PublishedBox extends CommentBox {
interface Binder extends UiBinder<HTMLPanel, PublishedBox> {} interface Binder extends UiBinder<HTMLPanel, PublishedBox> {}
private static UiBinder<HTMLPanel, CommentBox> uiBinder = private static UiBinder<HTMLPanel, CommentBox> uiBinder =
GWT.create(Binder.class); GWT.create(Binder.class);
PublishedBox(AccountInfo author, Timestamp when, String message, private DraftBox replyBox;
PublishedBox(CodeMirrorDemo host, PatchSet.Id id, CommentInfo info,
CommentLinkProcessor linkProcessor) { CommentLinkProcessor linkProcessor) {
super(uiBinder, author, when, message, linkProcessor, false); super(host, uiBinder, id, info, linkProcessor, false);
}
void registerReplyBox(DraftBox box) {
replyBox = box;
box.registerReplyToBox(this);
}
void unregisterReplyBox() {
replyBox = null;
}
private void openReplyBox() {
replyBox.setOpen(true);
replyBox.setEdit(true);
}
@UiHandler("reply")
void onReply(ClickEvent e) {
if (replyBox == null) {
DraftBox box = getDiffView().addReplyBox(getOriginal(), "", true);
registerReplyBox(box);
} else {
openReplyBox();
}
}
@UiHandler("replyDone")
void onReplyDone(ClickEvent e) {
if (replyBox == null) {
DraftBox box = getDiffView().addReplyBox(getOriginal(), "Done", false);
registerReplyBox(box);
} else {
openReplyBox();
}
} }
} }

View File

@@ -23,9 +23,9 @@ limitations under the License.
<g:HTMLPanel styleName='{res.style.contentPanel}'> <g:HTMLPanel styleName='{res.style.contentPanel}'>
<g:HTML ui:field='contentPanelMessage' styleName='{res.style.message}'></g:HTML> <g:HTML ui:field='contentPanelMessage' styleName='{res.style.message}'></g:HTML>
<div> <div>
<button ui:field='reply'><ui:msg>Reply ...</ui:msg></button> <g:Button ui:field='reply'><ui:msg>Reply ...</ui:msg></g:Button>
<button ui:field='replyDone'><ui:msg>Reply 'Done'</ui:msg></button> <g:Button ui:field='replyDone'><ui:msg>Reply 'Done'</ui:msg></g:Button>
</div> </div>
</g:HTMLPanel> </g:HTMLPanel>
</g:HTMLPanel> </g:HTMLPanel>
</ui:UiBinder> </ui:UiBinder>

View File

@@ -25,8 +25,8 @@ public class LineCharacter extends JavaScriptObject {
return lineCh; return lineCh;
} }
public final native void setLine(int line) /*-{ this.line = line; }-*/; private final native void setLine(int line) /*-{ this.line = line; }-*/;
public final native void setCh(int ch) /*-{ this.ch = ch; }-*/; private final native void setCh(int ch) /*-{ this.ch = ch; }-*/;
public final native int getLine() /*-{ return this.line; }-*/; public final native int getLine() /*-{ return this.line; }-*/;
public final native int getCh() /*-{ return this.ch; }-*/; public final native int getCh() /*-{ return this.ch; }-*/;