Start displaying comments and drafts.
Added drafts() call to CommentApi. Added CommentBox for displaying comments. Modified CodeMirrorDemo: 1. Implemented the algorithm and data structure that, given a line number on one CM, return the corresponding line number on the other. 2. Added methods to display comments. Modified some CSS styles for DiffTable. Added wrapper for LineWidget in case we need it. Change-Id: I9b9f6940ffa4eb1f87f79d5a655edd6beaab3b37
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
package com.google.gerrit.client.changes;
|
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.reviewdb.client.PatchSet;
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
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;
|
||||||
@@ -23,7 +24,41 @@ public class CommentApi {
|
|||||||
|
|
||||||
public static void comments(PatchSet.Id id,
|
public static void comments(PatchSet.Id id,
|
||||||
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) {
|
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) {
|
||||||
ChangeApi.revision(id).view("comments").get(cb);
|
revision(id, "comments").get(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void comment(PatchSet.Id id, String commentId,
|
||||||
|
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) {
|
||||||
|
revision(id, "comments").id(commentId).get(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drafts(PatchSet.Id id,
|
||||||
|
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) {
|
||||||
|
revision(id, "drafts").get(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void draft(PatchSet.Id id, String draftId,
|
||||||
|
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) {
|
||||||
|
revision(id, "drafts").id(draftId).get(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void createDraft(PatchSet.Id id, CommentInfo content,
|
||||||
|
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) {
|
||||||
|
revision(id, "drafts").put(content, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateDraft(PatchSet.Id id, String draftId,
|
||||||
|
CommentInfo content, AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) {
|
||||||
|
revision(id, "drafts").id(draftId).put(content, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteDraft(PatchSet.Id id, String draftId,
|
||||||
|
AsyncCallback<NativeMap<JsArray<CommentInfo>>> cb) {
|
||||||
|
revision(id, "drafts").id(draftId).delete(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RestApi revision(PatchSet.Id id, String type) {
|
||||||
|
return ChangeApi.revision(id).view(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommentApi() {
|
private CommentApi() {
|
||||||
|
|||||||
@@ -14,15 +14,22 @@
|
|||||||
|
|
||||||
package com.google.gerrit.client.diff;
|
package com.google.gerrit.client.diff;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.changes.CommentApi;
|
||||||
|
import com.google.gerrit.client.changes.CommentInfo;
|
||||||
import com.google.gerrit.client.diff.DiffInfo.Region;
|
import com.google.gerrit.client.diff.DiffInfo.Region;
|
||||||
import com.google.gerrit.client.diff.DiffInfo.Span;
|
import com.google.gerrit.client.diff.DiffInfo.Span;
|
||||||
import com.google.gerrit.client.rpc.CallbackGroup;
|
import com.google.gerrit.client.rpc.CallbackGroup;
|
||||||
import com.google.gerrit.client.rpc.GerritCallback;
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.client.rpc.NativeMap;
|
||||||
import com.google.gerrit.client.rpc.ScreenLoadCallback;
|
import com.google.gerrit.client.rpc.ScreenLoadCallback;
|
||||||
import com.google.gerrit.client.ui.Screen;
|
import com.google.gerrit.client.ui.Screen;
|
||||||
|
import com.google.gerrit.common.changes.Side;
|
||||||
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.core.client.JsArrayString;
|
import com.google.gwt.core.client.JsArrayString;
|
||||||
|
import com.google.gwt.core.client.Scheduler;
|
||||||
|
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||||
import com.google.gwt.dom.client.Element;
|
import com.google.gwt.dom.client.Element;
|
||||||
import com.google.gwt.dom.client.Style.Unit;
|
import com.google.gwt.dom.client.Style.Unit;
|
||||||
import com.google.gwt.event.logical.shared.ResizeEvent;
|
import com.google.gwt.event.logical.shared.ResizeEvent;
|
||||||
@@ -37,8 +44,13 @@ import net.codemirror.lib.Configuration;
|
|||||||
import net.codemirror.lib.LineCharacter;
|
import net.codemirror.lib.LineCharacter;
|
||||||
import net.codemirror.lib.ModeInjector;
|
import net.codemirror.lib.ModeInjector;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
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 =
|
||||||
|
JavaScriptObject.createArray().cast();
|
||||||
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;
|
||||||
@@ -47,6 +59,10 @@ public class CodeMirrorDemo extends Screen {
|
|||||||
private CodeMirror cmA;
|
private CodeMirror cmA;
|
||||||
private CodeMirror cmB;
|
private CodeMirror cmB;
|
||||||
private HandlerRegistration resizeHandler;
|
private HandlerRegistration resizeHandler;
|
||||||
|
private JsArray<CommentInfo> published;
|
||||||
|
private JsArray<CommentInfo> drafts;
|
||||||
|
private List<Runnable> resizeCallbacks;
|
||||||
|
private LineMapper mapper;
|
||||||
|
|
||||||
public CodeMirrorDemo(
|
public CodeMirrorDemo(
|
||||||
PatchSet.Id base,
|
PatchSet.Id base,
|
||||||
@@ -85,7 +101,7 @@ public class CodeMirrorDemo extends Screen {
|
|||||||
new ModeInjector()
|
new ModeInjector()
|
||||||
.add(getContentType(diff.meta_a()))
|
.add(getContentType(diff.meta_a()))
|
||||||
.add(getContentType(diff.meta_b()))
|
.add(getContentType(diff.meta_b()))
|
||||||
.inject(new ScreenLoadCallback<Void>(CodeMirrorDemo.this){
|
.inject(new ScreenLoadCallback<Void>(CodeMirrorDemo.this) {
|
||||||
@Override
|
@Override
|
||||||
protected void preDisplay(Void result) {
|
protected void preDisplay(Void result) {
|
||||||
display(diff);
|
display(diff);
|
||||||
@@ -93,6 +109,16 @@ public class CodeMirrorDemo extends Screen {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
CommentApi.comments(revision,
|
||||||
|
group.add(new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(NativeMap<JsArray<CommentInfo>> m) { published = m.get(path); }
|
||||||
|
}));
|
||||||
|
CommentApi.drafts(revision,
|
||||||
|
group.add(new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(NativeMap<JsArray<CommentInfo>> m) { drafts = m.get(path); }
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -105,6 +131,15 @@ public class CodeMirrorDemo extends Screen {
|
|||||||
cmB.refresh();
|
cmB.refresh();
|
||||||
}
|
}
|
||||||
Window.enableScrolling(false);
|
Window.enableScrolling(false);
|
||||||
|
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
for (Runnable r : resizeCallbacks) {
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
resizeCallbacks = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -129,6 +164,14 @@ public class CodeMirrorDemo extends Screen {
|
|||||||
cmA = displaySide(diff.meta_a(), diff.text_a(), diffTable.getCmA());
|
cmA = displaySide(diff.meta_a(), diff.text_a(), diffTable.getCmA());
|
||||||
cmB = displaySide(diff.meta_b(), diff.text_b(), diffTable.getCmB());
|
cmB = displaySide(diff.meta_b(), diff.text_b(), diffTable.getCmB());
|
||||||
render(diff);
|
render(diff);
|
||||||
|
resizeCallbacks = new ArrayList<Runnable>();
|
||||||
|
renderComments(published, false);
|
||||||
|
renderComments(drafts, true);
|
||||||
|
published = null;
|
||||||
|
drafts = null;
|
||||||
|
mapper = null;
|
||||||
|
|
||||||
|
// TODO: Probably need horizontal resize
|
||||||
resizeHandler = Window.addResizeHandler(new ResizeHandler() {
|
resizeHandler = Window.addResizeHandler(new ResizeHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onResize(ResizeEvent event) {
|
public void onResize(ResizeEvent event) {
|
||||||
@@ -159,40 +202,36 @@ public class CodeMirrorDemo extends Screen {
|
|||||||
.set("styleSelectedText", true)
|
.set("styleSelectedText", true)
|
||||||
.set("value", contents);
|
.set("value", contents);
|
||||||
final CodeMirror cm = CodeMirror.create(ele, cfg);
|
final CodeMirror cm = CodeMirror.create(ele, cfg);
|
||||||
cm.setWidth("100%");
|
|
||||||
cm.setHeight(Window.getClientHeight() - HEADER_FOOTER);
|
cm.setHeight(Window.getClientHeight() - HEADER_FOOTER);
|
||||||
return cm;
|
return cm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void render(DiffInfo diff) {
|
private void render(DiffInfo diff) {
|
||||||
JsArray<Region> regions = diff.content();
|
JsArray<Region> regions = diff.content();
|
||||||
int lineA = 0, lineB = 0;
|
mapper = new LineMapper();
|
||||||
for (int i = 0; i < regions.length(); i++) {
|
for (int i = 0; i < regions.length(); i++) {
|
||||||
Region current = regions.get(i);
|
Region current = regions.get(i);
|
||||||
if (current.ab() != null) {
|
int origLineA = mapper.getLineA();
|
||||||
lineA += current.ab().length();
|
int origLineB = mapper.getLineB();
|
||||||
lineB += current.ab().length();
|
if (current.ab() != null) { // Common
|
||||||
} else if (current.a() == null && current.b() != null) {
|
// TODO: Handle skips.
|
||||||
int delta = current.b().length();
|
mapper.appendCommon(current.ab().length());
|
||||||
insertEmptyLines(cmA, lineA, delta);
|
} else { // Insert, Delete or Edit
|
||||||
lineB = colorLines(cmB, lineB, delta);
|
JsArrayString currentA = current.a() == null ? EMPTY : current.a();
|
||||||
} else if (current.a() != null && current.b() == null) {
|
JsArrayString currentB = current.b() == null ? EMPTY : current.b();
|
||||||
int delta = current.a().length();
|
|
||||||
insertEmptyLines(cmB, lineB, delta);
|
|
||||||
lineA = colorLines(cmA, lineA, delta);
|
|
||||||
} else {
|
|
||||||
JsArrayString currentA = current.a();
|
|
||||||
JsArrayString currentB = current.b();
|
|
||||||
int aLength = currentA.length();
|
int aLength = currentA.length();
|
||||||
int bLength = currentB.length();
|
int bLength = currentB.length();
|
||||||
int origLineA = lineA;
|
colorLines(cmA, origLineA, aLength);
|
||||||
int origLineB = lineB;
|
colorLines(cmB, origLineB, bLength);
|
||||||
lineA = colorLines(cmA, lineA, aLength);
|
mapper.appendCommon(Math.min(aLength, bLength));
|
||||||
lineB = colorLines(cmB, lineB, bLength);
|
if (aLength < bLength) { // Edit with insertion
|
||||||
if (aLength < bLength) {
|
int insertCnt = bLength - aLength;
|
||||||
insertEmptyLines(cmA, lineA, bLength - aLength);
|
insertEmptyLines(cmA, mapper.getLineA(), insertCnt);
|
||||||
} else if (aLength > bLength) {
|
mapper.appendInsert(insertCnt);
|
||||||
insertEmptyLines(cmB, lineB, aLength - bLength);
|
} else if (aLength > bLength) { // Edit with deletion
|
||||||
|
int deleteCnt = aLength - bLength;
|
||||||
|
insertEmptyLines(cmB, mapper.getLineB(), deleteCnt);
|
||||||
|
mapper.appendDelete(deleteCnt);
|
||||||
}
|
}
|
||||||
markEdit(cmA, currentA, current.edit_a(), origLineA);
|
markEdit(cmA, currentA, current.edit_a(), origLineA);
|
||||||
markEdit(cmB, currentB, current.edit_b(), origLineB);
|
markEdit(cmB, currentB, current.edit_b(), origLineB);
|
||||||
@@ -200,25 +239,44 @@ public class CodeMirrorDemo extends Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertEmptyLines(CodeMirror cm, int line, int cnt) {
|
private void renderComments(JsArray<CommentInfo> comments, boolean isDraft) {
|
||||||
Element div = DOM.createDiv();
|
Configuration config = Configuration.create().set("coverGutter", true);
|
||||||
div.setClassName(diffTable.style.padding());
|
for (int i = 0; comments != null && i < comments.length(); i++) {
|
||||||
div.getStyle().setHeight(cnt, Unit.EM);
|
CommentInfo info = comments.get(i);
|
||||||
Configuration config = Configuration.create()
|
Side mySide = info.side();
|
||||||
.set("coverGutter", true)
|
CodeMirror cm = mySide == Side.PARENT ? cmA : cmB;
|
||||||
.set("above", line == 0);
|
CodeMirror other = otherCM(cm);
|
||||||
cm.addLineWidget(line == 0 ? 0 : (line - 1), div, config);
|
final CommentBox box = new CommentBox(info.author(), info.updated(),
|
||||||
|
info.message(), isDraft);
|
||||||
|
int line = info.line() - 1; // CommentInfo is 1-based, but CM is 0-based
|
||||||
|
diffTable.add(box);
|
||||||
|
cm.addLineWidget(line, box.getElement(), config);
|
||||||
|
int lineToPad = mapper.lineOnOther(mySide, line);
|
||||||
|
// Estimated height at 21px, fixed by deferring after display
|
||||||
|
final Element paddingOtherside = addPaddingWidget(other,
|
||||||
|
diffTable.style.padding(), lineToPad,
|
||||||
|
21, Unit.PX);
|
||||||
|
Runnable callback = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
paddingOtherside.getStyle().setHeight(
|
||||||
|
box.getOffsetHeight(), Unit.PX);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
resizeCallbacks.add(callback);
|
||||||
|
box.setOpenCloseHandler(callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int colorLines(CodeMirror cm, int line, int cnt) {
|
private CodeMirror otherCM(CodeMirror me) {
|
||||||
for (int i = 0; i < cnt; i++) {
|
return me == cmA ? cmB : cmA;
|
||||||
cm.addLineClass(line + i, LineClassWhere.WRAP, diffTable.style.diff());
|
|
||||||
}
|
|
||||||
return line + cnt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markEdit(CodeMirror cm, JsArrayString lines,
|
private void markEdit(CodeMirror cm, JsArrayString lines,
|
||||||
JsArray<Span> edits, int startLine) {
|
JsArray<Span> edits, int startLine) {
|
||||||
|
if (edits == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
EditIterator iter = new EditIterator(lines, startLine);
|
EditIterator iter = new EditIterator(lines, startLine);
|
||||||
Configuration diffOpt = Configuration.create()
|
Configuration diffOpt = Configuration.create()
|
||||||
.set("className", diffTable.style.diff())
|
.set("className", diffTable.style.diff())
|
||||||
@@ -246,8 +304,32 @@ public class CodeMirrorDemo extends Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Runnable doScroll(final CodeMirror cm) {
|
private void colorLines(CodeMirror cm, int line, int cnt) {
|
||||||
final CodeMirror other = cm == cmA ? cmB : cmA;
|
for (int i = 0; i < cnt; i++) {
|
||||||
|
cm.addLineClass(line + i, LineClassWhere.WRAP, diffTable.style.diff());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertEmptyLines(CodeMirror cm, int nextLine, int cnt) {
|
||||||
|
// -1 to compensate for the line we went past when this method is called.
|
||||||
|
addPaddingWidget(cm, diffTable.style.padding(), nextLine - 1,
|
||||||
|
cnt, Unit.EM);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Element addPaddingWidget(CodeMirror cm, String style, int line,
|
||||||
|
int height, Unit unit) {
|
||||||
|
Element div = DOM.createDiv();
|
||||||
|
div.setClassName(style);
|
||||||
|
div.getStyle().setHeight(height, unit);
|
||||||
|
Configuration config = Configuration.create()
|
||||||
|
.set("coverGutter", true)
|
||||||
|
.set("above", line == -1);
|
||||||
|
cm.addLineWidget(line == -1 ? 0 : line, div, config);
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Runnable doScroll(final CodeMirror cm) {
|
||||||
|
final CodeMirror other = otherCM(cm);
|
||||||
return new Runnable() {
|
return new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
cm.scrollToY(other.getScrollInfo().getTop());
|
cm.scrollToY(other.getScrollInfo().getTop());
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
//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.diff;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.AvatarImage;
|
||||||
|
import com.google.gerrit.client.FormatUtil;
|
||||||
|
import com.google.gerrit.client.account.AccountInfo;
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.dom.client.Element;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
|
import com.google.gwt.event.shared.HandlerRegistration;
|
||||||
|
import com.google.gwt.resources.client.CssResource;
|
||||||
|
import com.google.gwt.uibinder.client.UiBinder;
|
||||||
|
import com.google.gwt.uibinder.client.UiField;
|
||||||
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
|
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||||
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
/** An HtmlPanel holding the DialogBox to display a comment */
|
||||||
|
class CommentBox extends Composite {
|
||||||
|
interface Binder extends UiBinder<HTMLPanel, CommentBox> {}
|
||||||
|
private static Binder uiBinder = GWT.create(Binder.class);
|
||||||
|
|
||||||
|
interface CommentBoxStyle extends CssResource {
|
||||||
|
String open();
|
||||||
|
String close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private HandlerRegistration headerClick;
|
||||||
|
private Runnable clickCallback;
|
||||||
|
|
||||||
|
@UiField
|
||||||
|
Widget header;
|
||||||
|
|
||||||
|
@UiField
|
||||||
|
AvatarImage avatar;
|
||||||
|
|
||||||
|
@UiField
|
||||||
|
Element name;
|
||||||
|
|
||||||
|
@UiField
|
||||||
|
Element summary;
|
||||||
|
|
||||||
|
@UiField
|
||||||
|
Element date;
|
||||||
|
|
||||||
|
@UiField
|
||||||
|
Element contentPanel;
|
||||||
|
|
||||||
|
@UiField
|
||||||
|
Element contentPanelMessage;
|
||||||
|
|
||||||
|
@UiField
|
||||||
|
CommentBoxStyle style;
|
||||||
|
|
||||||
|
CommentBox(AccountInfo author, Timestamp when, String message,
|
||||||
|
boolean isDraft) {
|
||||||
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
// TODO: Format the comment box differently based on whether isDraft
|
||||||
|
// is true.
|
||||||
|
setAuthorNameText(author);
|
||||||
|
date.setInnerText(FormatUtil.shortFormatDayTime(when));
|
||||||
|
setMessageText(message);
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLoad() {
|
||||||
|
super.onLoad();
|
||||||
|
|
||||||
|
headerClick = header.addDomHandler(new ClickHandler() {
|
||||||
|
@Override
|
||||||
|
public void onClick(ClickEvent event) {
|
||||||
|
setOpen(!isOpen());
|
||||||
|
if (clickCallback != null) {
|
||||||
|
clickCallback.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, ClickEvent.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOpenCloseHandler(final Runnable callback) {
|
||||||
|
clickCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onUnload() {
|
||||||
|
super.onUnload();
|
||||||
|
|
||||||
|
if (headerClick != null) {
|
||||||
|
headerClick.removeHandler();
|
||||||
|
headerClick = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAuthorNameText(AccountInfo author) {
|
||||||
|
// TODO: Set avatar's display to none if we get a 404.
|
||||||
|
avatar = new AvatarImage(author, 26);
|
||||||
|
name.setInnerText(FormatUtil.name(author));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setMessageText(String message) {
|
||||||
|
if (message == null) {
|
||||||
|
message = "";
|
||||||
|
} else {
|
||||||
|
message = message.trim();
|
||||||
|
}
|
||||||
|
summary.setInnerText(message);
|
||||||
|
// TODO: Change to use setInnerHtml
|
||||||
|
contentPanelMessage.setInnerText(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setOpen(boolean open) {
|
||||||
|
if (open) {
|
||||||
|
removeStyleName(style.close());
|
||||||
|
addStyleName(style.open());
|
||||||
|
} else {
|
||||||
|
removeStyleName(style.open());
|
||||||
|
addStyleName(style.close());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOpen() {
|
||||||
|
return getStyleName().contains(style.open());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||||
|
xmlns:g='urn:import:com.google.gwt.user.client.ui'
|
||||||
|
xmlns:c='urn:import:com.google.gerrit.client'>
|
||||||
|
<ui:style type='com.google.gerrit.client.diff.CommentBox.CommentBoxStyle'>
|
||||||
|
.commentBox {
|
||||||
|
background-color: #e5ecf9;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
.summary {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
.summaryText {
|
||||||
|
color: #777;
|
||||||
|
height: 1em;
|
||||||
|
max-width: 80%;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.open .summaryText {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
width: 25%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.close .contentPanel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
</ui:style>
|
||||||
|
<g:HTMLPanel styleName='{style.commentBox}'>
|
||||||
|
<g:HTMLPanel ui:field='header'>
|
||||||
|
<table class='{style.table}'>
|
||||||
|
<tr>
|
||||||
|
<td><c:AvatarImage ui:field='avatar' /></td>
|
||||||
|
<td ui:field='name'></td>
|
||||||
|
<td class='{style.summary}'>
|
||||||
|
<div ui:field='summary' class='{style.summaryText}'></div>
|
||||||
|
</td>
|
||||||
|
<td ui:field='date' class='{style.date}'></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
<div ui:field='contentPanel' class='{style.contentPanel}'>
|
||||||
|
<div><p ui:field='contentPanelMessage' class='{style.message}'></p></div>
|
||||||
|
<div>
|
||||||
|
<button ui:field='reply'><ui:msg>Reply ...</ui:msg></button>
|
||||||
|
<button ui:field='replyDone'><ui:msg>Reply 'Done'</ui:msg></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
</ui:UiBinder>
|
||||||
@@ -15,12 +15,13 @@
|
|||||||
package com.google.gerrit.client.diff;
|
package com.google.gerrit.client.diff;
|
||||||
|
|
||||||
import com.google.gwt.core.client.GWT;
|
import com.google.gwt.core.client.GWT;
|
||||||
import com.google.gwt.dom.client.DivElement;
|
import com.google.gwt.dom.client.Element;
|
||||||
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.user.client.ui.Composite;
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||||
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A table with one row and two columns to hold the two CodeMirrors displaying
|
* A table with one row and two columns to hold the two CodeMirrors displaying
|
||||||
@@ -37,10 +38,10 @@ class DiffTable extends Composite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@UiField
|
@UiField
|
||||||
DivElement cmA;
|
Element cmA;
|
||||||
|
|
||||||
@UiField
|
@UiField
|
||||||
DivElement cmB;
|
Element cmB;
|
||||||
|
|
||||||
@UiField
|
@UiField
|
||||||
LineStyle style;
|
LineStyle style;
|
||||||
@@ -49,12 +50,15 @@ class DiffTable extends Composite {
|
|||||||
initWidget(uiBinder.createAndBindUi(this));
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
DivElement getCmA() {
|
Element getCmA() {
|
||||||
return cmA;
|
return cmA;
|
||||||
}
|
}
|
||||||
|
|
||||||
DivElement getCmB() {
|
Element getCmB() {
|
||||||
return cmB;
|
return cmB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add(Widget widget) {
|
||||||
|
((HTMLPanel) getWidget()).add(widget);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ limitations under the License.
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
.a, .b {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
.a .diff,
|
.a .diff,
|
||||||
.a .diff .CodeMirror-linenumber {
|
.a .diff .CodeMirror-linenumber {
|
||||||
background-color: #fee;
|
background-color: #fee;
|
||||||
@@ -52,10 +59,10 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
</ui:style>
|
</ui:style>
|
||||||
<g:HTMLPanel styleName='{style.difftable}'>
|
<g:HTMLPanel styleName='{style.difftable}'>
|
||||||
<table>
|
<table class='{style.table}'>
|
||||||
<tr>
|
<tr>
|
||||||
<td><div ui:field='cmA' class='{style.a}'></div></td>
|
<td ui:field='cmA' class='{style.a}'></td>
|
||||||
<td><div ui:field='cmB' class='{style.b}'></div></td>
|
<td ui:field='cmB' class='{style.b}'></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</g:HTMLPanel>
|
</g:HTMLPanel>
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
// 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.diff;
|
||||||
|
|
||||||
|
import com.google.gerrit.common.changes.Side;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Helper class to handle calculations involving line gaps. */
|
||||||
|
class LineMapper {
|
||||||
|
private int lineA;
|
||||||
|
private int lineB;
|
||||||
|
private List<LineGap> lineMapAtoB;
|
||||||
|
private List<LineGap> lineMapBtoA;
|
||||||
|
|
||||||
|
LineMapper() {
|
||||||
|
lineMapAtoB = new ArrayList<LineGap>();
|
||||||
|
lineMapBtoA = new ArrayList<LineGap>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLineA() {
|
||||||
|
return lineA;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLineB() {
|
||||||
|
return lineB;
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendCommon(int numLines) {
|
||||||
|
lineA += numLines;
|
||||||
|
lineB += numLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendInsert(int numLines) {
|
||||||
|
int origLineB = lineB;
|
||||||
|
lineB += numLines;
|
||||||
|
int bAheadOfA = lineB - lineA;
|
||||||
|
lineMapAtoB.add(new LineGap(lineA, lineA, bAheadOfA));
|
||||||
|
lineMapBtoA.add(new LineGap(origLineB, lineB - 1, -bAheadOfA));
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendDelete(int numLines) {
|
||||||
|
int origLineA = lineA;
|
||||||
|
lineA += numLines;
|
||||||
|
int aAheadOfB = lineA - lineB;
|
||||||
|
lineMapAtoB.add(new LineGap(origLineA, lineA - 1, -aAheadOfB));
|
||||||
|
lineMapBtoA.add(new LineGap(lineB, lineB, aAheadOfB));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to retrieve the line number on the other side.
|
||||||
|
*
|
||||||
|
* Given a line number on one side, performs a binary search in the lineMap
|
||||||
|
* to find the corresponding LineGap record.
|
||||||
|
*
|
||||||
|
* A LineGap records gap information from the start of an actual gap up to
|
||||||
|
* the start of the next gap. In the following example,
|
||||||
|
* lineMapAtoB will have LineGap: {start: 1, end: 1, delta: 3}
|
||||||
|
* (end doesn't really matter here, as the binary search only looks at start)
|
||||||
|
* lineMapBtoA will have LineGap: {start: 1, end: 3, delta: -3}
|
||||||
|
* These LineGaps control lines between 1 and 5.
|
||||||
|
*
|
||||||
|
* The "delta" is computed as the number to add on our side to get the line
|
||||||
|
* number on the other side given a line after the actual gap, so the result
|
||||||
|
* will be (line + delta). All lines within the actual gap (1 to 3) are
|
||||||
|
* considered corresponding to the last line above the region on the other
|
||||||
|
* side, which is 0 in this case. For these lines, we do (end + delta).
|
||||||
|
*
|
||||||
|
* For example, to get the line number on the left corresponding to 1 on the
|
||||||
|
* right (lineOnOther(REVISION, 1)), the method looks up in lineMapBtoA,
|
||||||
|
* finds the "delta" to be -3, and returns 3 + (-3) = 0 since 1 falls in the
|
||||||
|
* actual gap. On the other hand, the line corresponding to 5 on the right
|
||||||
|
* will be 5 + (-3) = 2, since 5 is in the region after the gap (but still
|
||||||
|
* controlled by the current LineGap).
|
||||||
|
*
|
||||||
|
* PARENT REVISION
|
||||||
|
* 0 | 0
|
||||||
|
* - | 1 \ \
|
||||||
|
* - | 2 | Actual insertion gap |
|
||||||
|
* - | 3 / | Region controlled by one LineGap
|
||||||
|
* 1 | 4 <- delta = 4 - 1 = 3 |
|
||||||
|
* 2 | 5 /
|
||||||
|
* - | 6
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
int lineOnOther(Side mySide, int line) {
|
||||||
|
List<LineGap> lineGaps = mySide == Side.PARENT ? lineMapAtoB : lineMapBtoA;
|
||||||
|
// Create a dummy LineGap for the search.
|
||||||
|
int ret = Collections.binarySearch(lineGaps, new LineGap(line));
|
||||||
|
if (ret == -1) {
|
||||||
|
return line;
|
||||||
|
} else {
|
||||||
|
LineGap lookup = lineGaps.get(0 <= ret ? ret : -ret - 2);
|
||||||
|
int end = lookup.end;
|
||||||
|
int delta = lookup.delta;
|
||||||
|
if (lookup.start <= line && line <= end) { // Line falls within gap
|
||||||
|
return end + delta;
|
||||||
|
} else { // Line after gap
|
||||||
|
return line + delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to record line gap info and assist in calculation of line
|
||||||
|
* number on the other side.
|
||||||
|
*
|
||||||
|
* For a mapping from A to B, where A is the side with an insertion:
|
||||||
|
* @field start The start line of the insertion in A.
|
||||||
|
* @field end The exclusive end line of the insertion in A.
|
||||||
|
* @field delta The offset added to A to get the line number in B calculated
|
||||||
|
* from end.
|
||||||
|
*/
|
||||||
|
private static class LineGap implements Comparable<LineGap> {
|
||||||
|
private final int start;
|
||||||
|
private final int end;
|
||||||
|
private final int delta;
|
||||||
|
|
||||||
|
private LineGap(int start, int end, int delta) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.delta = delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LineGap(int line) {
|
||||||
|
this(line, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(LineGap o) {
|
||||||
|
return start - o.start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,9 +66,18 @@ public class CodeMirror extends JavaScriptObject {
|
|||||||
this.addLineClass(line, where, lineClass);
|
this.addLineClass(line, where, lineClass);
|
||||||
}-*/;
|
}-*/;
|
||||||
|
|
||||||
public final native void addLineWidget(int line, Element node,
|
public final native void addWidget(LineCharacter pos, Element node,
|
||||||
|
boolean scrollIntoView) /*-{
|
||||||
|
this.addWidget(pos, node, scrollIntoView);
|
||||||
|
}-*/;
|
||||||
|
|
||||||
|
public final native LineWidget addLineWidget(int line, Element node,
|
||||||
Configuration options) /*-{
|
Configuration options) /*-{
|
||||||
this.addLineWidget(line, node, options);
|
return this.addLineWidget(line, node, options);
|
||||||
|
}-*/;
|
||||||
|
|
||||||
|
public final native int lineAtHeight(int height) /*-{
|
||||||
|
return this.lineAtHeight(height);
|
||||||
}-*/;
|
}-*/;
|
||||||
|
|
||||||
public final native void scrollTo(int x, int y) /*-{
|
public final native void scrollTo(int x, int y) /*-{
|
||||||
|
|||||||
31
gerrit-gwtui/src/main/java/net/codemirror/lib/LineWidget.java
vendored
Normal file
31
gerrit-gwtui/src/main/java/net/codemirror/lib/LineWidget.java
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
/** LineWidget objects used within CodeMirror. */
|
||||||
|
public class LineWidget extends JavaScriptObject {
|
||||||
|
public static LineWidget create() {
|
||||||
|
return createObject().cast();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final native void clear() /*-{ this.clear(); }-*/;
|
||||||
|
public final native void changed() /*-{ this.changed(); }-*/;
|
||||||
|
public final native JavaScriptObject getLine() /*-{ return this.line; }-*/;
|
||||||
|
|
||||||
|
protected LineWidget() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// 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.diff;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import com.google.gerrit.common.changes.Side;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/** Unit tests for LineMapper */
|
||||||
|
public class LineMapperTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAppendCommon() {
|
||||||
|
LineMapper mapper = new LineMapper();
|
||||||
|
mapper.appendCommon(10);
|
||||||
|
assertEquals(10, mapper.getLineA());
|
||||||
|
assertEquals(10, mapper.getLineB());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAppendInsert() {
|
||||||
|
LineMapper mapper = new LineMapper();
|
||||||
|
mapper.appendInsert(10);
|
||||||
|
assertEquals(0, mapper.getLineA());
|
||||||
|
assertEquals(10, mapper.getLineB());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAppendDelete() {
|
||||||
|
LineMapper mapper = new LineMapper();
|
||||||
|
mapper.appendDelete(10);
|
||||||
|
assertEquals(10, mapper.getLineA());
|
||||||
|
assertEquals(0, mapper.getLineB());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindInCommon() {
|
||||||
|
LineMapper mapper = new LineMapper();
|
||||||
|
mapper.appendCommon(10);
|
||||||
|
assertEquals(9, mapper.lineOnOther(Side.PARENT, 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindAfterCommon() {
|
||||||
|
LineMapper mapper = new LineMapper();
|
||||||
|
mapper.appendCommon(10);
|
||||||
|
assertEquals(10, mapper.lineOnOther(Side.PARENT, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindInInsertGap() {
|
||||||
|
LineMapper mapper = new LineMapper();
|
||||||
|
mapper.appendInsert(10);
|
||||||
|
assertEquals(-1, mapper.lineOnOther(Side.REVISION, 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindAfterInsertGap() {
|
||||||
|
LineMapper mapper = new LineMapper();
|
||||||
|
mapper.appendInsert(10);
|
||||||
|
assertEquals(0, mapper.lineOnOther(Side.REVISION, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindInDeleteGap() {
|
||||||
|
LineMapper mapper = new LineMapper();
|
||||||
|
mapper.appendDelete(10);
|
||||||
|
assertEquals(-1, mapper.lineOnOther(Side.PARENT, 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindAfterDeleteGap() {
|
||||||
|
LineMapper mapper = new LineMapper();
|
||||||
|
mapper.appendDelete(10);
|
||||||
|
assertEquals(0, mapper.lineOnOther(Side.PARENT, 10));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
VERSION = '3.13'
|
include_defs('//lib/maven.defs')
|
||||||
SHA1 = '7a83ae686d75afd30bb152d7683f2dc27e59ea82'
|
|
||||||
URL = 'http://codemirror.net/codemirror-%s.zip' % VERSION
|
VERSION = 'bb73aeacb8'
|
||||||
|
SHA1 = '3bc9c92b97210135bc83fca7a2bd5f3c4aab496a'
|
||||||
|
URL = GERRIT + 'net/codemirror/codemirror-%s.zip' % VERSION
|
||||||
|
|
||||||
prebuilt_jar(
|
prebuilt_jar(
|
||||||
name = 'codemirror',
|
name = 'codemirror',
|
||||||
|
|||||||
Reference in New Issue
Block a user