Add functionalities to CommentBox and fix various styles

- Added expandText() to DraftBox.
- Fixed CommentBox styles to make it look better. Added box-shadow.
- Adjusted CodeMirror's line height to avoid cutting off the bottom
  of text.
- Added refocusing on CM after clicking on CommentBoxes and SkipBars.
- Prevented feedback loop in synced scrolling.
- Fixed a bug in skip calculation.

Change-Id: I7cbe644f3a890cb6e62a5d83942a93411ea5550f
This commit is contained in:
Michael Zhou
2013-07-13 01:21:55 -07:00
parent 95b233df2d
commit 0485172aaa
15 changed files with 221 additions and 94 deletions

View File

@@ -226,10 +226,12 @@ public class CodeMirrorDemo extends Screen {
private void registerCmEvents(CodeMirror cm) {
cm.on("cursorActivity", updateActiveLine(cm));
cm.on("scroll", doScroll(otherCM(cm)));
cm.on("scroll", doScroll(cm));
/**
* TODO: Trying to prevent right click from updating the cursor.
* Doesn't seem to work for now.
* Trying to prevent right click from updating the cursor.
*
* TODO: Change to listen on "contextmenu" instead. Latest CM has
* provided a patch that will hopefully make this work.
*/
cm.on("mousedown", ignoreRightClick());
cm.addKeyMap(KeyMap.create().on("'u'", upToChange()));
@@ -238,7 +240,10 @@ public class CodeMirrorDemo extends Screen {
if (Gerrit.isSignedIn()) {
cm.addKeyMap(KeyMap.create().on("'c'", insertNewDraft(cm)));
}
// TODO: Examine if a better way exists.
/**
* TODO: Maybe remove this after updating CM to HEAD. The latest VIM mode
* doesn't enter INSERT mode when document is read only.
*/
for (String c : new String[]{"A", "C", "D", "I", "O", "P", "R", "S", "U",
"X", "Y", "~"}) {
CodeMirror.disableUnwantedKey("vim", c);
@@ -328,6 +333,7 @@ public class CodeMirrorDemo extends Screen {
.set("lineNumbers", true)
.set("tabSize", 2)
.set("mode", getContentType(meta))
.set("lineWrapping", true)
.set("styleSelectedText", true)
.set("showTrailingSpace", true)
.set("keyMap", "vim")
@@ -422,20 +428,20 @@ public class CodeMirrorDemo extends Screen {
return box;
}
CommentBox addCommentBox(CommentInfo info, final CommentBox box) {
CommentBox addCommentBox(CommentInfo info, CommentBox box) {
diffTable.add(box);
Side mySide = info.side();
CodeMirror cm = mySide == Side.PARENT ? cmA : cmB;
CodeMirror other = otherCM(cm);
CodeMirror other = otherCm(cm);
int line = info.line() - 1; // CommentInfo is 1-based, but CM is 0-based
LineHandle handle = cm.getLineHandle(line);
PaddingManager manager;
if (linePaddingManagerMap.containsKey(handle)) {
manager = linePaddingManagerMap.get(handle);
} else {
// Estimated height at 21px, fixed by deferring after display
// Estimated height at 28px, fixed by deferring after display
manager = new PaddingManager(
addPaddingWidget(cm, DiffTable.style.padding(), line, 21, Unit.PX, 0));
addPaddingWidget(cm, DiffTable.style.padding(), line, 28, Unit.PX, 0));
linePaddingManagerMap.put(handle, manager);
}
int lineToPad = mapper.lineOnOther(mySide, line).getLine();
@@ -444,7 +450,7 @@ public class CodeMirrorDemo extends Screen {
PaddingManager.link(manager, linePaddingManagerMap.get(otherHandle));
} else {
PaddingManager otherManager = new PaddingManager(
addPaddingWidget(other, DiffTable.style.padding(), lineToPad, 21, Unit.PX, 0));
addPaddingWidget(other, DiffTable.style.padding(), lineToPad, 28, Unit.PX, 0));
linePaddingManagerMap.put(otherHandle, otherManager);
PaddingManager.link(manager, otherManager);
}
@@ -484,13 +490,14 @@ public class CodeMirrorDemo extends Screen {
private void renderPublished() {
List<CommentInfo> sorted = sortComment(published);
for (CommentInfo info : sorted) {
final PublishedBox box =
new PublishedBox(this, revision, info, commentLinkProcessor);
CodeMirror cm = getCmFromSide(info.side());
PublishedBox box =
new PublishedBox(this, cm, revision, info, commentLinkProcessor);
box.setOpen(false);
initialBoxes.add(box);
publishedMap.put(info.id(), box);
int line = info.line() - 1;
LineHandle handle = getCmFromSide(info.side()).getLineHandle(line);
LineHandle handle = cm.getLineHandle(line);
lineLastPublishedBoxMap.put(handle, box);
lineActiveBoxMap.put(handle, box);
addCommentBox(info, box);
@@ -500,7 +507,7 @@ public class CodeMirrorDemo extends Screen {
private void renderDrafts() {
List<CommentInfo> sorted = sortComment(drafts);
for (CommentInfo info : sorted) {
final DraftBox box =
DraftBox box =
new DraftBox(this, getCmFromSide(info.side()), revision, info,
commentLinkProcessor, false, false);
box.setOpen(false);
@@ -529,7 +536,7 @@ public class CodeMirrorDemo extends Screen {
int boxLine = info.line();
int deltaBefore = boxLine - startLine;
int deltaAfter = startLine + skip.getSize() - boxLine;
if (deltaBefore < 0 || deltaAfter < 0) {
if (deltaBefore < -context || deltaAfter < -context) {
temp.add(skip);
} else if (deltaBefore > context && deltaAfter > context) {
SkippedLine before = new SkippedLine(
@@ -584,7 +591,7 @@ public class CodeMirrorDemo extends Screen {
return bar;
}
private CodeMirror otherCM(CodeMirror me) {
private CodeMirror otherCm(CodeMirror me) {
return me == cmA ? cmB : cmA;
}
@@ -633,11 +640,11 @@ public class CodeMirrorDemo extends Screen {
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, null);
1.1 * cnt, Unit.EM, null);
}
private LineWidgetElementPair addPaddingWidget(CodeMirror cm, String style,
int line, int height, Unit unit, Integer index) {
int line, double height, Unit unit, Integer index) {
Element div = DOM.createDiv();
div.setClassName(style);
div.getStyle().setHeight(height, unit);
@@ -652,16 +659,23 @@ public class CodeMirrorDemo extends Screen {
}
private Runnable doScroll(final CodeMirror cm) {
final CodeMirror other = otherCM(cm);
final CodeMirror other = otherCm(cm);
return new Runnable() {
public void run() {
cm.scrollToY(other.getScrollInfo().getTop());
// Prevent feedback loop, Chrome seems fine but Firefox chokes.
double now = (double) System.currentTimeMillis();
if (cm.getScrollSetBy() == other && cm.getScrollSetAt() + 50 > now) {
return;
}
other.scrollToY(cm.getScrollInfo().getTop());
other.setScrollSetBy(cm);
other.setScrollSetAt(now);
}
};
}
private Runnable updateActiveLine(final CodeMirror cm) {
final CodeMirror other = otherCM(cm);
final CodeMirror other = otherCm(cm);
return new Runnable() {
public void run() {
if (cm.hasActiveLine()) {
@@ -793,7 +807,7 @@ public class CodeMirrorDemo extends Screen {
}
@Override
public void onKeyPress(final KeyPressEvent event) {
public void onKeyPress(KeyPressEvent event) {
}
}
}

View File

@@ -20,6 +20,8 @@ import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
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;
@@ -30,6 +32,7 @@ import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
import net.codemirror.lib.CodeMirror;
import net.codemirror.lib.LineWidget;
import java.sql.Timestamp;
@@ -48,6 +51,9 @@ abstract class CommentBox extends Composite {
private CodeMirrorDemo diffView;
private boolean draft;
private LineWidget selfWidget;
private CodeMirror cm;
private HandlerRegistration regClick;
private ClickHandler clickFocusHandler;
@UiField(provided=true)
CommentBoxHeader header;
@@ -60,24 +66,27 @@ abstract class CommentBox extends Composite {
CommentBox(
CodeMirrorDemo host,
CodeMirror cmInstance,
UiBinder<? extends Widget, CommentBox> binder,
PatchSet.Id id, CommentInfo info, CommentLinkProcessor linkProcessor,
boolean isDraft) {
diffView = host;
cm = cmInstance;
commentLinkProcessor = linkProcessor;
original = info;
patchSetId = id;
draft = isDraft;
header = new CommentBoxHeader(info.author(), info.updated(), isDraft);
initWidget(binder.createAndBindUi(this));
setMessageText(info.message());
}
@Override
protected void onLoad() {
super.onLoad();
clickFocusHandler = new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
cm.focus();
}
};
enableClickFocusHandler();
res.style().ensureInjected();
setMessageText(info.message());
}
void resizePaddingWidget() {
@@ -160,8 +169,26 @@ abstract class CommentBox extends Composite {
return selfWidget;
}
CodeMirror getCm() {
return cm;
}
@UiHandler("header")
void onHeaderClick(ClickEvent e) {
setOpen(!isOpen());
cm.focus();
}
void enableClickFocusHandler() {
if (regClick == null) {
regClick = addDomHandler(clickFocusHandler, ClickEvent.getType());
}
}
void disableClickFocusHandler() {
if (regClick != null) {
regClick.removeHandler();
regClick = null;
}
}
}

View File

@@ -55,17 +55,23 @@ class CommentBoxHeader extends Composite implements HasClickHandlers {
Element date;
CommentBoxHeader(AccountInfo author, Timestamp when, boolean isDraft) {
// TODO: Set avatar's display to none if we get a 404.
avatar = author == null ? new AvatarImage() : new AvatarImage(author, 26);
if (author != null) {
avatar = new AvatarImage(author, 26);
avatar.setSize("", "");
} else {
avatar = new AvatarImage();
}
initWidget(uiBinder.createAndBindUi(this));
this.draft = isDraft;
draft = isDraft;
if (when != null) {
setDate(when);
}
if (isDraft) {
name.setInnerText("(Draft)");
name.setInnerText(PatchUtil.C.draft());
} else {
name.setInnerText(FormatUtil.name(author));
name.setTitle(FormatUtil.nameEmail(author));
date.setTitle(FormatUtil.mediumFormat(when));
}
}

View File

@@ -22,7 +22,7 @@ limitations under the License.
<table class='{res.style.table}'>
<tr>
<td><c:AvatarImage ui:field='avatar' /></td>
<td ui:field='name'></td>
<td ui:field='name' class='{res.style.name}'></td>
<td class='{res.style.summary}'>
<div ui:field='summary' class='{res.style.summaryText}'></div>
</td>

View File

@@ -29,10 +29,12 @@ interface CommentBoxResources extends ClientBundle {
String close();
String commentBox();
String table();
String name();
String summary();
String summaryText();
String date();
String contentPanel();
String message();
String button();
}
}

View File

@@ -1,6 +1,14 @@
.commentBox {
background-color: #e5ecf9;
border: 1px solid black;
-webkit-box-shadow: 3px 3px 3px #888888;
-moz-box-shadow: 3px 3px 3px #888888;
box-shadow: 3px 3px 3px #888888;
margin-bottom: 5px;
margin-right: 5px;
overflow: visible;
word-wrap: break-word;
overflow-wrap: break-word;
}
.table {
@@ -9,6 +17,11 @@
table-layout: fixed;
}
.name {
width: 20%;
font-weight: bold;
}
.summary {
width: 60%;
}
@@ -18,7 +31,7 @@
height: 1em;
max-width: 80%;
overflow: hidden;
padding-bottom: 1px;
padding-bottom: 2px;
text-overflow: ellipsis;
white-space: nowrap;
}
@@ -37,5 +50,11 @@
}
.message {
margin: 5px;
margin-left: 5px;
margin-right: 5px;
}
.button {
margin-left: 5px;
margin-bottom: 5px;
}

View File

@@ -24,6 +24,7 @@ limitations under the License.
@external .cm-searching, .cm-trailingspace;
.difftable .CodeMirror pre {
padding: 0;
padding-bottom: 0.1em;
overflow: hidden;
}
.table {
@@ -60,7 +61,7 @@ limitations under the License.
}
.activeLine .CodeMirror-linenumber,
.activeLine .diff, .activeLine .intralineBg {
background-color: #E0FFFF;
background-color: #E0FFFF !important;
}
.activeLineBg {
background-color: #E0FFFF !important;
@@ -74,11 +75,14 @@ limitations under the License.
.CodeMirror-selectedtext {
background-color: inherit !important;
}
.difftable .CodeMirror-linenumber {
height: 1.1em;
}
.hideNumber .CodeMirror-linenumber {
color: transparent;
background-color: #def;
width: 23px !important;
height: 16px;
height: 1.3em;
}
.difftable .CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
opacity: 0.8;

View File

@@ -24,16 +24,15 @@ 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.DoubleClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
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.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwtexpui.globalkey.client.NpTextArea;
@@ -70,10 +69,13 @@ class DraftBox extends CommentBox {
@UiField
Button discard;
private HandlerRegistration messageClick;
private static final int INITIAL_COLS = 60;
private static final int INITIAL_LINES = 5;
private static final int MAX_LINES = 30;
private boolean isNew;
private PublishedBox replyToBox;
private CodeMirror cm;
private Timer expandTimer;
DraftBox(
CodeMirrorDemo host,
@@ -81,46 +83,46 @@ class DraftBox extends CommentBox {
PatchSet.Id id,
CommentInfo info,
CommentLinkProcessor linkProcessor,
boolean isNew,
boolean isNewDraft,
boolean saveOnInit) {
super(host, uiBinder, id, info, linkProcessor, true);
super(host, cm, uiBinder, id, info, linkProcessor, true);
this.cm = cm;
this.isNew = isNew;
editArea.setText(contentPanelMessage.getText());
isNew = isNewDraft;
editArea.setText(info.message());
editArea.setCharacterWidth(INITIAL_COLS);
editArea.setVisibleLines(INITIAL_LINES);
editArea.setSpellCheck(true);
if (saveOnInit) {
onSave(null);
}
if (isNew) {
addStyleName(draftStyle.newDraft());
}
}
@Override
protected void onLoad() {
super.onLoad();
messageClick = contentPanelMessage.addDoubleClickHandler(
new DoubleClickHandler() {
expandTimer = new Timer() {
@Override
public void onDoubleClick(DoubleClickEvent arg0) {
setEdit(true);
public void run() {
expandText();
}
});
};
addDomHandler(new MouseMoveHandler() {
@Override
public void onMouseMove(MouseMoveEvent arg0) {
public void onMouseMove(MouseMoveEvent event) {
resizePaddingWidget();
}
}, MouseMoveEvent.getType());
}
@Override
protected void onUnload() {
super.onUnload();
messageClick.removeHandler();
messageClick = null;
private void expandText() {
double cols = editArea.getCharacterWidth();
int rows = 2;
for (String line : editArea.getText().split("\n")) {
rows += Math.ceil((1.0 + line.length()) / cols);
}
rows = Math.max(INITIAL_LINES, Math.min(rows, MAX_LINES));
if (editArea.getVisibleLines() != rows) {
editArea.setVisibleLines(rows);
}
resizePaddingWidget();
}
void setEdit(boolean edit) {
@@ -128,11 +130,15 @@ class DraftBox extends CommentBox {
setOpen(true);
removeStyleName(draftStyle.view());
addStyleName(draftStyle.edit());
editArea.setText(contentPanelMessage.getText());
editArea.setText(getOriginal().message());
expandText();
editArea.setFocus(true);
disableClickFocusHandler();
} else {
expandTimer.cancel();
removeStyleName(draftStyle.edit());
addStyleName(draftStyle.view());
enableClickFocusHandler();
}
resizePaddingWidget();
}
@@ -142,6 +148,7 @@ class DraftBox extends CommentBox {
}
private void removeUI() {
expandTimer.cancel();
if (replyToBox != null) {
replyToBox.unregisterReplyBox();
}
@@ -152,7 +159,12 @@ class DraftBox extends CommentBox {
PaddingManager manager = getPaddingManager();
manager.remove(this);
manager.resizePaddingWidget();
cm.focus();
getCm().focus();
}
@UiHandler("contentPanelMessage")
void onDoubleClick(DoubleClickEvent e) {
setEdit(true);
}
@UiHandler("edit")
@@ -187,13 +199,13 @@ class DraftBox extends CommentBox {
} else {
CommentApi.updateDraft(getPatchSetId(), original.id(), input, cb);
}
cm.focus();
getCm().focus();
}
@UiHandler("cancel")
void onCancel(ClickEvent e) {
setEdit(false);
cm.focus();
getCm().focus();
}
@UiHandler("discard")
@@ -213,10 +225,17 @@ class DraftBox extends CommentBox {
@UiHandler("editArea")
void onCtrlS(KeyDownEvent e) {
if (e.isControlKeyDown() && e.getNativeKeyCode() == 83) {
onSave(null);
e.preventDefault();
if ((e.isControlKeyDown() || e.isMetaKeyDown())
&& !e.isAltKeyDown() && !e.isShiftKeyDown()) {
switch (e.getNativeKeyCode()) {
case 's':
case 'S':
e.preventDefault();
onSave(null);
return;
}
}
expandTimer.schedule(250);
}
/** TODO: Unused now. Re-enable this after implementing auto-save */

View File

@@ -23,6 +23,10 @@ limitations under the License.
.edit .messagePanel {
display: none;
}
textarea.editArea {
margin-left: 5px;
margin-bottom: 2px;
}
.view .editArea {
display: none;
}
@@ -30,27 +34,27 @@ limitations under the License.
display: none;
}
</ui:style>
<g:HTMLPanel styleName='{res.style.commentBox}'>
<g:HTMLPanel addStyleNames='{res.style.commentBox}'>
<d:CommentBoxHeader ui:field='header' />
<div class='{res.style.contentPanel}'>
<c:NpTextArea ui:field='editArea' styleName='{draftStyle.editArea}'/>
<div>
<g:Button ui:field='save' styleName='{draftStyle.editArea}'>
<c:NpTextArea ui:field='editArea' addStyleNames='{draftStyle.editArea}'/>
<div class='{res.style.button}'>
<g:Button ui:field='save' addStyleNames='{draftStyle.editArea}'>
<ui:msg>Save</ui:msg>
</g:Button>
<g:Button ui:field='cancel'
styleName='{draftStyle.editArea} {draftStyle.cancel}'>
addStyleNames='{draftStyle.editArea} {draftStyle.cancel}'>
<ui:msg>Cancel</ui:msg>
</g:Button>
<g:Button ui:field='discard' styleName='{draftStyle.editArea}'>
<g:Button ui:field='discard' addStyleNames='{draftStyle.editArea}'>
<ui:msg>Discard</ui:msg>
</g:Button>
</div>
</div>
<div class='{res.style.contentPanel}'>
<g:HTML ui:field='contentPanelMessage'
styleName='{res.style.message} {draftStyle.messagePanel}'></g:HTML>
<g:Button ui:field='edit' styleName='{draftStyle.messagePanel}'>
addStyleNames='{res.style.message} {draftStyle.messagePanel}'></g:HTML>
<g:Button ui:field='edit' addStyleNames='{draftStyle.messagePanel} {res.style.button}'>
<ui:msg>Edit</ui:msg>
</g:Button>
</div>

View File

@@ -58,7 +58,7 @@ class PaddingManager {
private int getMyTotalHeight() {
int total = 0;
for (CommentBox box : comments) {
total += box.getOffsetHeight();
total += box.getOffsetHeight() + 5; // 5px for shadow margin
}
return total;
}

View File

@@ -23,6 +23,8 @@ import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.HTMLPanel;
import net.codemirror.lib.CodeMirror;
/** An HtmlPanel for displaying a published comment */
class PublishedBox extends CommentBox {
interface Binder extends UiBinder<HTMLPanel, PublishedBox> {}
@@ -31,9 +33,13 @@ class PublishedBox extends CommentBox {
private DraftBox replyBox;
PublishedBox(CodeMirrorDemo host, PatchSet.Id id, CommentInfo info,
PublishedBox(
CodeMirrorDemo host,
CodeMirror cm,
PatchSet.Id id,
CommentInfo info,
CommentLinkProcessor linkProcessor) {
super(host, uiBinder, id, info, linkProcessor, false);
super(host, cm, uiBinder, id, info, linkProcessor, false);
}
void registerReplyBox(DraftBox box) {

View File

@@ -18,11 +18,11 @@ limitations under the License.
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:d='urn:import:com.google.gerrit.client.diff'>
<ui:with field='res' type='com.google.gerrit.client.diff.CommentBoxResources' />
<g:HTMLPanel styleName='{res.style.commentBox}'>
<g:HTMLPanel addStyleNames='{res.style.commentBox}'>
<d:CommentBoxHeader ui:field='header' />
<g:HTMLPanel styleName='{res.style.contentPanel}'>
<g:HTML ui:field='contentPanelMessage' styleName='{res.style.message}'></g:HTML>
<div>
<g:HTMLPanel addStyleNames='{res.style.contentPanel}'>
<g:HTML ui:field='contentPanelMessage' addStyleNames='{res.style.message}'></g:HTML>
<div class='{res.style.button}'>
<g:Button ui:field='reply'><ui:msg>Reply ...</ui:msg></g:Button>
<g:Button ui:field='replyDone'><ui:msg>Reply 'Done'</ui:msg></g:Button>
</div>

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.client.diff;
import com.google.gerrit.client.patches.PatchUtil;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
@@ -65,12 +66,18 @@ class SkipBar extends Composite {
private CodeMirror cm;
private int numSkipLines;
SkipBar(CodeMirror cm) {
this.cm = cm;
SkipBar(CodeMirror cmInstance) {
cm = cmInstance;
skipNum = new Anchor(true);
upArrow = new Anchor(true);
downArrow = new Anchor(true);
initWidget(uiBinder.createAndBindUi(this));
addDomHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
cm.focus();
}
}, ClickEvent.getType());
}
void setWidget(LineWidget widget) {

View File

@@ -19,6 +19,8 @@ limitations under the License.
<ui:style type='com.google.gerrit.client.diff.SkipBar.SkipBarStyle'>
.skipBar {
background-color: #def;
height: 1.3em;
overflow: hidden;
}
.text {
display: table;
@@ -38,16 +40,16 @@ limitations under the License.
display: none;
}
</ui:style>
<g:HTMLPanel styleName='{style.skipBar}'>
<g:HTMLPanel addStyleNames='{style.skipBar}'>
<div class='{style.text}'>
<ui:msg>
<g:Anchor ui:field='upArrow' styleName='{style.anchor}'>
<g:Anchor ui:field='upArrow' addStyleNames='{style.anchor}'>
</g:Anchor>
<span>... skipped </span>
<g:Anchor ui:field='skipNum' styleName='{style.anchor}'>
<span><ui:msg>... skipped </ui:msg></span>
<g:Anchor ui:field='skipNum' addStyleNames='{style.anchor}'>
</g:Anchor>
<span> common lines ...</span>
<g:Anchor ui:field='downArrow' styleName='{style.anchor}'>
<span><ui:msg> common lines ...</ui:msg></span>
<g:Anchor ui:field='downArrow' addStyleNames='{style.anchor}'>
</g:Anchor>
</ui:msg>
</div>

View File

@@ -128,12 +128,29 @@ public class CodeMirror extends JavaScriptObject {
return this.getScrollInfo();
}-*/;
public final native CodeMirror getScrollSetBy() /*-{
return this.state.scrollSetBy;
}-*/;
public final native void setScrollSetBy(CodeMirror cm) /*-{
this.state.scrollSetBy = cm;
}-*/;
public final native double getScrollSetAt() /*-{
return this.state.scrollSetAt;
}-*/;
public final native void setScrollSetAt(double when) /*-{
this.state.scrollSetAt = when;
}-*/;
public final native void on(String event, Runnable thunk) /*-{
this.on(event, $entry(function() {
thunk.@java.lang.Runnable::run()();
}));
}-*/;
/** TODO: Break this line after updating GWT */
public final native void on(String event, EventHandler handler) /*-{
this.on(event, $entry(function(cm, e) {
handler.@net.codemirror.lib.CodeMirror.EventHandler::handle(Lnet/codemirror/lib/CodeMirror;Lcom/google/gwt/dom/client/NativeEvent;)(cm, e);