SideBySide2: Rewrite comment box UI
Use absolute positioned divs similar to the way the message history on ChangeScreen2 is organized. This is slightly smaller and faster DOM for the browser to handle, and works reasonably well for the comments. The new UI is fewer lines of code, uses less vertical screen space, and fixes a number of layout glitches and interaction issues. Change-Id: If6b382ef7ae57ebc811074a37fa17928020403be
This commit is contained in:
@@ -15,148 +15,43 @@
|
||||
package com.google.gerrit.client.diff;
|
||||
|
||||
import com.google.gerrit.client.changes.CommentInfo;
|
||||
import com.google.gerrit.client.ui.CommentLinkProcessor;
|
||||
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;
|
||||
import com.google.gwt.uibinder.client.UiHandler;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.HTML;
|
||||
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;
|
||||
|
||||
/** An HtmlPanel for displaying a comment */
|
||||
abstract class CommentBox extends Composite {
|
||||
interface CommentBoxStyle extends CssResource {
|
||||
String open();
|
||||
String close();
|
||||
static {
|
||||
Resources.I.style().ensureInjected();
|
||||
}
|
||||
|
||||
private CommentLinkProcessor commentLinkProcessor;
|
||||
private CommentInfo original;
|
||||
private PatchSet.Id patchSetId;
|
||||
private PaddingManager widgetManager;
|
||||
private SideBySide2 diffView;
|
||||
private boolean draft;
|
||||
private LineWidget selfWidget;
|
||||
private CodeMirror cm;
|
||||
private HandlerRegistration regClick;
|
||||
private ClickHandler clickFocusHandler;
|
||||
|
||||
@UiField(provided=true)
|
||||
CommentBoxHeader header;
|
||||
|
||||
@UiField
|
||||
HTML contentPanelMessage;
|
||||
|
||||
@UiField
|
||||
CommentBoxResources res;
|
||||
|
||||
CommentBox(
|
||||
SideBySide2 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));
|
||||
clickFocusHandler = new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
cm.focus();
|
||||
}
|
||||
};
|
||||
enableClickFocusHandler();
|
||||
res.style().ensureInjected();
|
||||
setMessageText(info.message());
|
||||
}
|
||||
|
||||
void resizePaddingWidget() {
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand(){
|
||||
public void execute() {
|
||||
if (selfWidget == null || widgetManager == null) {
|
||||
throw new IllegalStateException(
|
||||
"resizePaddingWidget() called before setting up widgets");
|
||||
}
|
||||
assert selfWidget != null;
|
||||
assert widgetManager != null;
|
||||
selfWidget.changed();
|
||||
widgetManager.resizePaddingWidget();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setMessageText(String message) {
|
||||
if (message == null) {
|
||||
message = "";
|
||||
} else {
|
||||
message = message.trim();
|
||||
}
|
||||
header.setSummaryText(message);
|
||||
SafeHtml buf = new SafeHtmlBuilder().append(message).wikify();
|
||||
buf = commentLinkProcessor.apply(buf);
|
||||
SafeHtml.set(contentPanelMessage, buf);
|
||||
}
|
||||
|
||||
void setDate(Timestamp when) {
|
||||
header.setDate(when);
|
||||
}
|
||||
abstract CommentInfo getCommentInfo();
|
||||
abstract boolean isOpen();
|
||||
|
||||
void setOpen(boolean open) {
|
||||
if (open) {
|
||||
removeStyleName(res.style().close());
|
||||
addStyleName(res.style().open());
|
||||
} else {
|
||||
removeStyleName(res.style().open());
|
||||
addStyleName(res.style().close());
|
||||
}
|
||||
resizePaddingWidget();
|
||||
}
|
||||
|
||||
boolean isOpen() {
|
||||
return getStyleName().contains(res.style().open());
|
||||
}
|
||||
|
||||
SideBySide2 getDiffView() {
|
||||
return diffView;
|
||||
}
|
||||
|
||||
PatchSet.Id getPatchSetId() {
|
||||
return patchSetId;
|
||||
}
|
||||
|
||||
CommentInfo getOriginal() {
|
||||
return original;
|
||||
}
|
||||
|
||||
void updateOriginal(CommentInfo newInfo) {
|
||||
original = newInfo;
|
||||
}
|
||||
|
||||
PaddingManager getPaddingManager() {
|
||||
return widgetManager;
|
||||
}
|
||||
|
||||
boolean isDraft() {
|
||||
return draft;
|
||||
}
|
||||
|
||||
void setPaddingManager(PaddingManager manager) {
|
||||
widgetManager = manager;
|
||||
}
|
||||
@@ -168,27 +63,4 @@ abstract class CommentBox extends Composite {
|
||||
LineWidget getSelfWidget() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
//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.gerrit.client.patches.PatchUtil;
|
||||
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.dom.client.HasClickHandlers;
|
||||
import com.google.gwt.event.dom.client.LoadEvent;
|
||||
import com.google.gwt.event.dom.client.LoadHandler;
|
||||
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.UIObject;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* An HtmlPanel representing the header of a CommentBox, displaying
|
||||
* the author's avatar (if applicable), the author's name, the summary,
|
||||
* and the date.
|
||||
*/
|
||||
class CommentBoxHeader extends Composite implements HasClickHandlers {
|
||||
interface Binder extends UiBinder<HTMLPanel, CommentBoxHeader> {}
|
||||
private static Binder uiBinder = GWT.create(Binder.class);
|
||||
|
||||
interface CommentBoxHeaderStyle extends CssResource {
|
||||
String name();
|
||||
String summary();
|
||||
String date();
|
||||
}
|
||||
|
||||
private boolean draft;
|
||||
|
||||
@UiField
|
||||
Element avatarCell;
|
||||
|
||||
@UiField(provided=true)
|
||||
AvatarImage avatar;
|
||||
|
||||
@UiField
|
||||
Element name;
|
||||
|
||||
@UiField
|
||||
Element summary;
|
||||
|
||||
@UiField
|
||||
Element date;
|
||||
|
||||
@UiField
|
||||
CommentBoxHeaderStyle headerStyle;
|
||||
|
||||
CommentBoxHeader(AccountInfo author, Timestamp when, boolean isDraft) {
|
||||
if (author != null) {
|
||||
avatar = new AvatarImage(author, 26);
|
||||
avatar.setSize("", "");
|
||||
} else {
|
||||
avatar = new AvatarImage();
|
||||
}
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
UIObject.setVisible(avatarCell, false);
|
||||
avatar.addLoadHandler(new LoadHandler() {
|
||||
@Override
|
||||
public void onLoad(LoadEvent event) {
|
||||
UIObject.setVisible(avatarCell, true);
|
||||
}
|
||||
});
|
||||
draft = isDraft;
|
||||
if (when != null) {
|
||||
setDate(when);
|
||||
}
|
||||
if (isDraft) {
|
||||
name.setInnerText(PatchUtil.C.draft());
|
||||
} else {
|
||||
name.setInnerText(FormatUtil.name(author));
|
||||
name.setTitle(FormatUtil.nameEmail(author));
|
||||
date.setTitle(FormatUtil.mediumFormat(when));
|
||||
}
|
||||
}
|
||||
|
||||
void setDate(Timestamp when) {
|
||||
if (draft) {
|
||||
date.setInnerText(PatchUtil.M.draftSaved(when));
|
||||
} else {
|
||||
date.setInnerText(FormatUtil.shortFormatDayTime(when));
|
||||
}
|
||||
}
|
||||
|
||||
void setSummaryText(String message) {
|
||||
summary.setInnerText(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerRegistration addClickHandler(ClickHandler handler) {
|
||||
return addDomHandler(handler, ClickEvent.getType());
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<?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:with field='res' type='com.google.gerrit.client.diff.CommentBoxResources' />
|
||||
<ui:style field='headerStyle'
|
||||
type='com.google.gerrit.client.diff.CommentBoxHeader.CommentBoxHeaderStyle'>
|
||||
.avatarCell {
|
||||
width: 26px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.name {
|
||||
width: 15%;
|
||||
font-weight: bold;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.summary {
|
||||
width: 60%;
|
||||
}
|
||||
.date {
|
||||
width: 15%;
|
||||
text-align: right;
|
||||
}
|
||||
</ui:style>
|
||||
<g:HTMLPanel>
|
||||
<table class='{res.style.table}'>
|
||||
<tr>
|
||||
<td ui:field='avatarCell' class='{headerStyle.avatarCell}'>
|
||||
<c:AvatarImage ui:field='avatar' />
|
||||
</td>
|
||||
<td ui:field='name' class='{headerStyle.name}'></td>
|
||||
<td class='{headerStyle.summary}'>
|
||||
<div ui:field='summary' class='{res.style.summaryText}'></div>
|
||||
</td>
|
||||
<td ui:field='date' class='{headerStyle.date}'></td>
|
||||
</tr>
|
||||
</table>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
@@ -1,45 +1,78 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
.commentBox {
|
||||
background-color: #e5ecf9;
|
||||
position: relative;
|
||||
width: 679px;
|
||||
font-family: sans-serif;
|
||||
background-color: #fcfa96;
|
||||
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 {
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
table-layout: fixed;
|
||||
}
|
||||
.header { cursor: pointer; }
|
||||
|
||||
.summaryText {
|
||||
.summary {
|
||||
color: #777;
|
||||
height: 1em;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 120px;
|
||||
width: 408px;
|
||||
overflow: hidden;
|
||||
padding-bottom: 2px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.open .summaryText {
|
||||
display: none;
|
||||
.date {
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.close .contentPanel {
|
||||
display: none;
|
||||
.contents {
|
||||
margin-left: 28px;
|
||||
position: relative;
|
||||
}
|
||||
.contents p,
|
||||
.contents ul {
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0.3em;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
.commentBox button {
|
||||
margin-right: 3px;
|
||||
margin-bottom: 1px;
|
||||
padding: 1px;
|
||||
text-align: center;
|
||||
font-size: 8px;
|
||||
font-weight: bold;
|
||||
border: 1px solid black;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
background-color: #4d90fe;
|
||||
background-image: -webkit-linear-gradient(top, #4d90fe, #4d90fe);
|
||||
-webkit-border-radius: 2px;
|
||||
-webkit-box-sizing: content-box;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-left: 5px;
|
||||
margin-bottom: 5px;
|
||||
.commentBox button div {
|
||||
width: 25px;
|
||||
white-space: nowrap;
|
||||
color: #fff;
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package com.google.gerrit.client.diff;
|
||||
|
||||
import com.google.gerrit.client.FormatUtil;
|
||||
import com.google.gerrit.client.changes.CommentApi;
|
||||
import com.google.gerrit.client.changes.CommentInfo;
|
||||
import com.google.gerrit.client.changes.CommentInput;
|
||||
@@ -22,88 +23,99 @@ 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.JavaScriptObject;
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
|
||||
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.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.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.HTML;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.UIObject;
|
||||
import com.google.gwtexpui.globalkey.client.NpTextArea;
|
||||
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
|
||||
|
||||
import net.codemirror.lib.CodeMirror;
|
||||
|
||||
/** An HtmlPanel for displaying and editing a draft */
|
||||
class DraftBox extends CommentBox {
|
||||
interface Binder extends UiBinder<HTMLPanel, DraftBox> {}
|
||||
private static UiBinder<HTMLPanel, CommentBox> uiBinder =
|
||||
GWT.create(Binder.class);
|
||||
private static Binder uiBinder = GWT.create(Binder.class);
|
||||
|
||||
interface DraftBoxStyle extends CssResource {
|
||||
String edit();
|
||||
String view();
|
||||
String newDraft();
|
||||
}
|
||||
|
||||
@UiField
|
||||
NpTextArea editArea;
|
||||
|
||||
@UiField
|
||||
Button edit;
|
||||
|
||||
@UiField
|
||||
Button save;
|
||||
|
||||
@UiField
|
||||
Button cancel;
|
||||
|
||||
@UiField
|
||||
Button discard;
|
||||
|
||||
@UiField
|
||||
DraftBoxStyle draftStyle;
|
||||
|
||||
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 final SideBySide2 parent;
|
||||
private final CodeMirror cm;
|
||||
private final CommentLinkProcessor linkProcessor;
|
||||
private final PatchSet.Id psId;
|
||||
private CommentInfo comment;
|
||||
private PublishedBox replyToBox;
|
||||
private Timer expandTimer;
|
||||
|
||||
DraftBox(
|
||||
SideBySide2 host,
|
||||
CodeMirror cm,
|
||||
PatchSet.Id id,
|
||||
CommentInfo info,
|
||||
CommentLinkProcessor linkProcessor,
|
||||
boolean isNewDraft,
|
||||
boolean saveOnInit) {
|
||||
super(host, cm, uiBinder, id, info, linkProcessor, true);
|
||||
@UiField Element summary;
|
||||
@UiField Element date;
|
||||
|
||||
@UiField Element p_view;
|
||||
@UiField HTML message;
|
||||
@UiField Button edit;
|
||||
@UiField Button discard1;
|
||||
|
||||
@UiField Element p_edit;
|
||||
@UiField NpTextArea editArea;
|
||||
@UiField Button save;
|
||||
@UiField Button cancel;
|
||||
@UiField Button discard2;
|
||||
|
||||
DraftBox(
|
||||
SideBySide2 parent,
|
||||
CodeMirror cm,
|
||||
CommentLinkProcessor clp,
|
||||
PatchSet.Id id,
|
||||
CommentInfo info) {
|
||||
this.parent = parent;
|
||||
this.cm = cm;
|
||||
this.linkProcessor = clp;
|
||||
this.psId = id;
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
isNew = isNewDraft;
|
||||
editArea.setText(info.message());
|
||||
editArea.setCharacterWidth(INITIAL_COLS);
|
||||
editArea.setVisibleLines(INITIAL_LINES);
|
||||
editArea.setSpellCheck(true);
|
||||
expandTimer = new Timer() {
|
||||
@Override
|
||||
public void run() {
|
||||
expandText();
|
||||
}
|
||||
};
|
||||
if (saveOnInit) {
|
||||
onSave(null);
|
||||
}
|
||||
if (isNew) {
|
||||
addStyleName(draftStyle.newDraft());
|
||||
}
|
||||
set(info);
|
||||
|
||||
addDomHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
if (!isEdit()) {
|
||||
setOpen(!isOpen());
|
||||
}
|
||||
}
|
||||
}, ClickEvent.getType());
|
||||
addDomHandler(new DoubleClickHandler() {
|
||||
@Override
|
||||
public void onDoubleClick(DoubleClickEvent event) {
|
||||
if (isEdit()) {
|
||||
editArea.setFocus(true);
|
||||
} else {
|
||||
setOpen(true);
|
||||
setEdit(true);
|
||||
}
|
||||
}
|
||||
}, DoubleClickEvent.getType());
|
||||
addDomHandler(new MouseMoveHandler() {
|
||||
@Override
|
||||
public void onMouseMove(MouseMoveEvent event) {
|
||||
@@ -112,10 +124,38 @@ class DraftBox extends CommentBox {
|
||||
}, MouseMoveEvent.getType());
|
||||
}
|
||||
|
||||
private void set(CommentInfo info) {
|
||||
date.setInnerText(FormatUtil.shortFormatDayTime(info.updated()));
|
||||
if (info.message() != null) {
|
||||
String msg = info.message().trim();
|
||||
summary.setInnerText(msg);
|
||||
message.setHTML(linkProcessor.apply(
|
||||
new SafeHtmlBuilder().append(msg).wikify()));
|
||||
}
|
||||
this.comment = info;
|
||||
}
|
||||
|
||||
@Override
|
||||
CommentInfo getCommentInfo() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isOpen() {
|
||||
return UIObject.isVisible(p_view);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setOpen(boolean open) {
|
||||
UIObject.setVisible(summary, !open);
|
||||
UIObject.setVisible(p_view, open);
|
||||
super.setOpen(open);
|
||||
}
|
||||
|
||||
private void expandText() {
|
||||
double cols = editArea.getCharacterWidth();
|
||||
int rows = 2;
|
||||
for (String line : editArea.getText().split("\n")) {
|
||||
for (String line : editArea.getValue().split("\n")) {
|
||||
rows += Math.ceil((1.0 + line.length()) / cols);
|
||||
}
|
||||
rows = Math.max(INITIAL_LINES, Math.min(rows, MAX_LINES));
|
||||
@@ -125,22 +165,33 @@ class DraftBox extends CommentBox {
|
||||
resizePaddingWidget();
|
||||
}
|
||||
|
||||
private boolean isEdit() {
|
||||
return UIObject.isVisible(p_edit);
|
||||
}
|
||||
|
||||
void setEdit(boolean edit) {
|
||||
UIObject.setVisible(summary, false);
|
||||
UIObject.setVisible(p_view, !edit);
|
||||
UIObject.setVisible(p_edit, edit);
|
||||
|
||||
if (edit) {
|
||||
setOpen(true);
|
||||
removeStyleName(draftStyle.view());
|
||||
addStyleName(draftStyle.edit());
|
||||
editArea.setText(getOriginal().message());
|
||||
expandText();
|
||||
editArea.setReadOnly(false);
|
||||
final String msg = comment.message() != null
|
||||
? comment.message().trim()
|
||||
: "";
|
||||
editArea.setValue(msg);
|
||||
editArea.setFocus(true);
|
||||
disableClickFocusHandler();
|
||||
expandText();
|
||||
if (msg.length() > 0) {
|
||||
Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
|
||||
@Override
|
||||
public boolean execute() {
|
||||
editArea.setCursorPos(msg.length());
|
||||
return false;
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
} else {
|
||||
expandTimer.cancel();
|
||||
editArea.setReadOnly(true);
|
||||
removeStyleName(draftStyle.edit());
|
||||
addStyleName(draftStyle.view());
|
||||
enableClickFocusHandler();
|
||||
}
|
||||
resizePaddingWidget();
|
||||
}
|
||||
@@ -149,75 +200,113 @@ class DraftBox extends CommentBox {
|
||||
replyToBox = box;
|
||||
}
|
||||
|
||||
private void removeUI() {
|
||||
setEdit(false);
|
||||
@Override
|
||||
protected void onUnload() {
|
||||
expandTimer.cancel();
|
||||
super.onUnload();
|
||||
}
|
||||
|
||||
private void removeUI() {
|
||||
if (replyToBox != null) {
|
||||
replyToBox.unregisterReplyBox();
|
||||
}
|
||||
CommentInfo info = getOriginal();
|
||||
getDiffView().removeDraft(this, info.side(), info.line() - 1);
|
||||
parent.removeDraft(this, comment.side(), comment.line() - 1);
|
||||
|
||||
removeFromParent();
|
||||
getSelfWidget().clear();
|
||||
|
||||
PaddingManager manager = getPaddingManager();
|
||||
manager.remove(this);
|
||||
manager.resizePaddingWidget();
|
||||
getCm().focus();
|
||||
cm.focus();
|
||||
}
|
||||
|
||||
@UiHandler("contentPanelMessage")
|
||||
void onDoubleClick(DoubleClickEvent e) {
|
||||
@UiHandler("message")
|
||||
void onMessageClick(ClickEvent e) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
@UiHandler("message")
|
||||
void onMessageDoubleClick(DoubleClickEvent e) {
|
||||
setEdit(true);
|
||||
}
|
||||
|
||||
@UiHandler("edit")
|
||||
void onEdit(ClickEvent e) {
|
||||
e.stopPropagation();
|
||||
setEdit(true);
|
||||
}
|
||||
|
||||
@UiHandler("save")
|
||||
void onSave(ClickEvent e) {
|
||||
final String message = editArea.getText();
|
||||
if (message.equals("")) {
|
||||
e.stopPropagation();
|
||||
onSave();
|
||||
}
|
||||
|
||||
private void onSave() {
|
||||
String message = editArea.getValue().trim();
|
||||
if (message.length() == 0) {
|
||||
return;
|
||||
}
|
||||
CommentInfo original = getOriginal();
|
||||
|
||||
CommentInfo original = comment;
|
||||
CommentInput input = CommentInput.create(original);
|
||||
input.setMessage(message);
|
||||
setEdit(false);
|
||||
enableEdit(false);
|
||||
|
||||
GerritCallback<CommentInfo> cb = new GerritCallback<CommentInfo>() {
|
||||
@Override
|
||||
public void onSuccess(CommentInfo result) {
|
||||
updateOriginal(result);
|
||||
setMessageText(message);
|
||||
setDate(result.updated());
|
||||
if (isNew) {
|
||||
removeStyleName(draftStyle.newDraft());
|
||||
isNew = false;
|
||||
enableEdit(true);
|
||||
set(result);
|
||||
if (result.message().length() < 70) {
|
||||
UIObject.setVisible(p_edit, false);
|
||||
setOpen(false);
|
||||
} else {
|
||||
setEdit(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
enableEdit(true);
|
||||
super.onFailure(e);
|
||||
}
|
||||
};
|
||||
if (isNew) {
|
||||
CommentApi.createDraft(getPatchSetId(), input, cb);
|
||||
if (original.id() == null) {
|
||||
CommentApi.createDraft(psId, input, cb);
|
||||
} else {
|
||||
CommentApi.updateDraft(getPatchSetId(), original.id(), input, cb);
|
||||
CommentApi.updateDraft(psId, original.id(), input, cb);
|
||||
}
|
||||
getCm().focus();
|
||||
cm.focus();
|
||||
}
|
||||
|
||||
private void enableEdit(boolean on) {
|
||||
editArea.setEnabled(on);
|
||||
save.setEnabled(on);
|
||||
cancel.setEnabled(on);
|
||||
discard2.setEnabled(on);
|
||||
}
|
||||
|
||||
@UiHandler("cancel")
|
||||
void onCancel(ClickEvent e) {
|
||||
setEdit(false);
|
||||
getCm().focus();
|
||||
}
|
||||
|
||||
@UiHandler("discard")
|
||||
void onDiscard(ClickEvent e) {
|
||||
if (isNew) {
|
||||
e.stopPropagation();
|
||||
if (comment.id() == null && editArea.getValue().length() == 0) {
|
||||
removeUI();
|
||||
} else {
|
||||
setEdit(false);
|
||||
CommentApi.deleteDraft(getPatchSetId(), getOriginal().id(),
|
||||
cm.focus();
|
||||
}
|
||||
}
|
||||
|
||||
@UiHandler({"discard1", "discard2"})
|
||||
void onDiscard(ClickEvent e) {
|
||||
e.stopPropagation();
|
||||
if (comment.id() == null) {
|
||||
removeUI();
|
||||
} else {
|
||||
setEdit(false);
|
||||
CommentApi.deleteDraft(psId, comment.id(),
|
||||
new GerritCallback<JavaScriptObject>() {
|
||||
@Override
|
||||
public void onSuccess(JavaScriptObject result) {
|
||||
@@ -228,29 +317,21 @@ class DraftBox extends CommentBox {
|
||||
}
|
||||
|
||||
@UiHandler("editArea")
|
||||
void onCtrlS(KeyDownEvent e) {
|
||||
void onKeyDown(KeyDownEvent e) {
|
||||
if ((e.isControlKeyDown() || e.isMetaKeyDown())
|
||||
&& !e.isAltKeyDown() && !e.isShiftKeyDown()) {
|
||||
switch (e.getNativeKeyCode()) {
|
||||
case 's':
|
||||
case 'S':
|
||||
e.preventDefault();
|
||||
onSave(null);
|
||||
onSave();
|
||||
return;
|
||||
}
|
||||
} else if (e.getNativeKeyCode() == KeyCodes.KEY_ESCAPE
|
||||
&& comment.id() == null && editArea.getValue().length() == 0) {
|
||||
removeUI();
|
||||
return;
|
||||
}
|
||||
expandTimer.schedule(250);
|
||||
}
|
||||
|
||||
/** TODO: Unused now. Re-enable this after implementing auto-save */
|
||||
void onEsc(KeyDownEvent e) {
|
||||
if (e.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
|
||||
if (isNew) {
|
||||
removeUI();
|
||||
} else {
|
||||
onCancel(null);
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,49 +14,82 @@ 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:d='urn:import:com.google.gerrit.client.diff'
|
||||
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'>
|
||||
<ui:with field='res' type='com.google.gerrit.client.diff.CommentBoxResources' />
|
||||
<ui:style field='draftStyle' type='com.google.gerrit.client.diff.DraftBox.DraftBoxStyle'>
|
||||
.edit .messagePanel {
|
||||
display: none;
|
||||
<ui:UiBinder
|
||||
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||
xmlns:c='urn:import:com.google.gerrit.client'
|
||||
xmlns:e='urn:import:com.google.gwtexpui.globalkey.client'
|
||||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||
<ui:with field='res' type='com.google.gerrit.client.diff.Resources'/>
|
||||
<ui:style>
|
||||
.draft {
|
||||
width: 45px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
background-color: #aaa;
|
||||
}
|
||||
textarea.editArea {
|
||||
margin-left: 5px;
|
||||
margin-bottom: 2px;
|
||||
.editArea { max-width: 637px; }
|
||||
button.button div {
|
||||
width: 35px;
|
||||
}
|
||||
.view .editArea {
|
||||
display: none;
|
||||
}
|
||||
.newDraft .cancel {
|
||||
display: none;
|
||||
button.discard {
|
||||
color: #d14836;
|
||||
background-color: #d14836;
|
||||
background-image: -webkit-linear-gradient(top, #d14836, #d14836);
|
||||
position: absolute;
|
||||
left: 150px;
|
||||
}
|
||||
</ui:style>
|
||||
<g:HTMLPanel addStyleNames='{res.style.commentBox}'>
|
||||
<d:CommentBoxHeader ui:field='header' />
|
||||
<div class='{res.style.contentPanel}'>
|
||||
<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'
|
||||
addStyleNames='{draftStyle.editArea} {draftStyle.cancel}'>
|
||||
<ui:msg>Cancel</ui:msg>
|
||||
</g:Button>
|
||||
<g:Button ui:field='discard' addStyleNames='{draftStyle.editArea}'>
|
||||
<ui:msg>Discard</ui:msg>
|
||||
</g:Button>
|
||||
|
||||
<g:HTMLPanel styleName='{res.style.commentBox}'>
|
||||
<div class='{res.style.contents}'>
|
||||
<div class='{res.style.header}'>
|
||||
<div class='{style.draft}'>Draft</div>
|
||||
<div ui:field='summary' class='{res.style.summary}'/>
|
||||
<div ui:field='date' class='{res.style.date}'/>
|
||||
</div>
|
||||
<div ui:field='p_view' aria-hidden='true' style='display: NONE'>
|
||||
<g:HTML ui:field='message' styleName=''/>
|
||||
<div style='position: relative'>
|
||||
<g:Button ui:field='edit'
|
||||
title='Edit this draft comment'
|
||||
styleName='{style.button}'>
|
||||
<ui:attribute name='title'/>
|
||||
<div><ui:msg>Edit</ui:msg></div>
|
||||
</g:Button>
|
||||
<g:Button ui:field='discard1'
|
||||
title='Discard this draft comment'
|
||||
styleName='{style.button}'
|
||||
addStyleNames='{style.discard}'>
|
||||
<ui:attribute name='title'/>
|
||||
<div><ui:msg>Discard</ui:msg></div>
|
||||
</g:Button>
|
||||
</div>
|
||||
</div>
|
||||
<div ui:field='p_edit' aria-hidden='true' style='display: NONE'>
|
||||
<e:NpTextArea ui:field='editArea'
|
||||
characterWidth='60'
|
||||
visibleLines='5'
|
||||
spellCheck='true'
|
||||
styleName='{style.editArea}'/>
|
||||
<div style='position: relative'>
|
||||
<g:Button ui:field='save'
|
||||
title='Save this draft comment'
|
||||
styleName='{style.button}'>
|
||||
<ui:attribute name='title'/>
|
||||
<div><ui:msg>Save</ui:msg></div>
|
||||
</g:Button>
|
||||
<g:Button ui:field='cancel' styleName='{style.button}'>
|
||||
<div><ui:msg>Cancel</ui:msg></div>
|
||||
</g:Button>
|
||||
<g:Button ui:field='discard2'
|
||||
title='Discard this draft comment'
|
||||
styleName='{style.button}'
|
||||
addStyleNames='{style.discard}'>
|
||||
<ui:attribute name='title'/>
|
||||
<div><ui:msg>Discard</ui:msg></div>
|
||||
</g:Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='{res.style.contentPanel}'>
|
||||
<g:HTML ui:field='contentPanelMessage'
|
||||
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>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
@@ -14,33 +14,109 @@
|
||||
|
||||
package com.google.gerrit.client.diff;
|
||||
|
||||
import com.google.gerrit.client.AvatarImage;
|
||||
import com.google.gerrit.client.FormatUtil;
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
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.changes.Util;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
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.dom.client.Element;
|
||||
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;
|
||||
import com.google.gwt.uibinder.client.UiHandler;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
|
||||
import net.codemirror.lib.CodeMirror;
|
||||
import com.google.gwt.user.client.ui.UIObject;
|
||||
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
|
||||
|
||||
/** An HtmlPanel for displaying a published comment */
|
||||
class PublishedBox extends CommentBox {
|
||||
interface Binder extends UiBinder<HTMLPanel, PublishedBox> {}
|
||||
private static UiBinder<HTMLPanel, CommentBox> uiBinder =
|
||||
GWT.create(Binder.class);
|
||||
private static Binder uiBinder = GWT.create(Binder.class);
|
||||
|
||||
static interface Style extends CssResource {
|
||||
String closed();
|
||||
}
|
||||
|
||||
private final SideBySide2 parent;
|
||||
private final PatchSet.Id psId;
|
||||
private final CommentInfo comment;
|
||||
private DraftBox replyBox;
|
||||
|
||||
@UiField Style style;
|
||||
@UiField Element name;
|
||||
@UiField Element summary;
|
||||
@UiField Element date;
|
||||
@UiField Element message;
|
||||
@UiField Element buttons;
|
||||
@UiField Button reply;
|
||||
@UiField Button done;
|
||||
|
||||
@UiField(provided = true)
|
||||
AvatarImage avatar;
|
||||
|
||||
PublishedBox(
|
||||
SideBySide2 host,
|
||||
CodeMirror cm,
|
||||
PatchSet.Id id,
|
||||
CommentInfo info,
|
||||
CommentLinkProcessor linkProcessor) {
|
||||
super(host, cm, uiBinder, id, info, linkProcessor, false);
|
||||
SideBySide2 parent,
|
||||
CommentLinkProcessor clp,
|
||||
PatchSet.Id psId,
|
||||
CommentInfo info) {
|
||||
this.parent = parent;
|
||||
this.psId = psId;
|
||||
this.comment = info;
|
||||
|
||||
if (info.author() != null) {
|
||||
avatar = new AvatarImage(info.author(), 26);
|
||||
avatar.setSize("", "");
|
||||
} else {
|
||||
avatar = new AvatarImage();
|
||||
}
|
||||
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
addDomHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
setOpen(!isOpen());
|
||||
}
|
||||
}, ClickEvent.getType());
|
||||
|
||||
name.setInnerText(authorName(info));
|
||||
date.setInnerText(FormatUtil.shortFormatDayTime(info.updated()));
|
||||
if (info.message() != null) {
|
||||
String msg = info.message().trim();
|
||||
summary.setInnerText(msg);
|
||||
message.setInnerSafeHtml(clp.apply(
|
||||
new SafeHtmlBuilder().append(msg).wikify()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
CommentInfo getCommentInfo() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isOpen() {
|
||||
return UIObject.isVisible(message);
|
||||
}
|
||||
|
||||
void setOpen(boolean open) {
|
||||
UIObject.setVisible(summary, !open);
|
||||
UIObject.setVisible(message, open);
|
||||
UIObject.setVisible(buttons, open);
|
||||
if (open) {
|
||||
removeStyleName(style.closed());
|
||||
} else {
|
||||
addStyleName(style.closed());
|
||||
}
|
||||
super.setOpen(open);
|
||||
}
|
||||
|
||||
void registerReplyBox(DraftBox box) {
|
||||
@@ -59,25 +135,47 @@ class PublishedBox extends CommentBox {
|
||||
|
||||
@UiHandler("reply")
|
||||
void onReply(ClickEvent e) {
|
||||
e.stopPropagation();
|
||||
if (!Gerrit.isSignedIn()) {
|
||||
Gerrit.doSignIn(getDiffView().getToken());
|
||||
Gerrit.doSignIn(parent.getToken());
|
||||
} else if (replyBox == null) {
|
||||
DraftBox box = getDiffView().addReply(getOriginal(), "", false);
|
||||
registerReplyBox(box);
|
||||
registerReplyBox(parent.addDraftBox(parent.createReply(comment)));
|
||||
} else {
|
||||
openReplyBox();
|
||||
}
|
||||
}
|
||||
|
||||
@UiHandler("replyDone")
|
||||
@UiHandler("done")
|
||||
void onReplyDone(ClickEvent e) {
|
||||
e.stopPropagation();
|
||||
if (!Gerrit.isSignedIn()) {
|
||||
Gerrit.doSignIn(getDiffView().getToken());
|
||||
Gerrit.doSignIn(parent.getToken());
|
||||
} else if (replyBox == null) {
|
||||
DraftBox box = getDiffView().addReply(getOriginal(), "Done", true);
|
||||
registerReplyBox(box);
|
||||
done.setEnabled(false);
|
||||
CommentInput input = CommentInput.create(parent.createReply(comment));
|
||||
input.setMessage("Done");
|
||||
CommentApi.createDraft(psId, input,
|
||||
new GerritCallback<CommentInfo>() {
|
||||
@Override
|
||||
public void onSuccess(CommentInfo result) {
|
||||
done.setEnabled(true);
|
||||
setOpen(false);
|
||||
registerReplyBox(parent.addDraftBox(result));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
openReplyBox();
|
||||
setOpen(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static String authorName(CommentInfo info) {
|
||||
if (info.author() != null) {
|
||||
if (info.author().name() != null) {
|
||||
return info.author().name();
|
||||
}
|
||||
return Gerrit.getConfig().getAnonymousCowardName();
|
||||
}
|
||||
return Util.C.messageNoAuthor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,18 +14,58 @@ 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:d='urn:import:com.google.gerrit.client.diff'>
|
||||
<ui:with field='res' type='com.google.gerrit.client.diff.CommentBoxResources' />
|
||||
<g:HTMLPanel addStyleNames='{res.style.commentBox}'>
|
||||
<d:CommentBoxHeader ui:field='header' />
|
||||
<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>
|
||||
<ui:UiBinder
|
||||
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||
xmlns:c='urn:import:com.google.gerrit.client'
|
||||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||
<ui:with field='res' type='com.google.gerrit.client.diff.Resources'/>
|
||||
<ui:style type='com.google.gerrit.client.diff.PublishedBox.Style'>
|
||||
.avatar {
|
||||
position: absolute;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
}
|
||||
.closed .avatar {
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.name {
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
}
|
||||
.closed .name {
|
||||
width: 120px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-weight: normal;
|
||||
}
|
||||
</ui:style>
|
||||
|
||||
<g:HTMLPanel
|
||||
styleName='{res.style.commentBox}'
|
||||
addStyleNames='{style.closed}'>
|
||||
<c:AvatarImage ui:field='avatar' styleName='{style.avatar}'/>
|
||||
<div class='{res.style.contents}'>
|
||||
<div class='{res.style.header}'>
|
||||
<div ui:field='name' class='{style.name}'/>
|
||||
<div ui:field='summary' class='{res.style.summary}'/>
|
||||
<div ui:field='date' class='{res.style.date}'/>
|
||||
</div>
|
||||
</g:HTMLPanel>
|
||||
<div ui:field='message' aria-hidden='true' style='display: NONE'/>
|
||||
<div ui:field='buttons' aria-hidden='true' style='display: NONE'>
|
||||
<g:Button ui:field='reply' styleName=''
|
||||
title='Reply to this comment'>
|
||||
<ui:attribute name='title'/>
|
||||
<div><ui:msg>Reply</ui:msg></div>
|
||||
</g:Button>
|
||||
<g:Button ui:field='done' styleName=''
|
||||
title='Reply "Done" to this comment'>
|
||||
<ui:attribute name='title'/>
|
||||
<div><ui:msg>Done</ui:msg></div>
|
||||
</g:Button>
|
||||
</div>
|
||||
</div>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
|
||||
@@ -14,24 +14,21 @@
|
||||
|
||||
package com.google.gerrit.client.diff;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.resources.client.ClientBundle;
|
||||
import com.google.gwt.resources.client.CssResource;
|
||||
|
||||
/**
|
||||
* Resources used by diff.
|
||||
*/
|
||||
interface CommentBoxResources extends ClientBundle {
|
||||
@Source("CommentBoxUi.css")
|
||||
Style style();
|
||||
/** Resources used by diff. */
|
||||
interface Resources extends ClientBundle {
|
||||
static final Resources I = GWT.create(Resources.class);
|
||||
|
||||
@Source("CommentBoxUi.css") Style style();
|
||||
|
||||
interface Style extends CssResource {
|
||||
String open();
|
||||
String close();
|
||||
String commentBox();
|
||||
String table();
|
||||
String summaryText();
|
||||
String contentPanel();
|
||||
String message();
|
||||
String button();
|
||||
String contents();
|
||||
String header();
|
||||
String summary();
|
||||
String date();
|
||||
}
|
||||
}
|
||||
@@ -460,34 +460,29 @@ public class SideBySide2 extends Screen {
|
||||
}
|
||||
|
||||
private DraftBox addNewDraft(CodeMirror cm, int line) {
|
||||
Side side = getSideFromCm(cm);
|
||||
CommentInfo info = CommentInfo.create(
|
||||
return addDraftBox(CommentInfo.create(
|
||||
path,
|
||||
side,
|
||||
getSideFromCm(cm),
|
||||
line + 1,
|
||||
null,
|
||||
null);
|
||||
return addDraftBox(info, false);
|
||||
null));
|
||||
}
|
||||
|
||||
DraftBox addReply(CommentInfo replyTo, String initMessage, boolean doSave) {
|
||||
Side side = replyTo.side();
|
||||
int line = replyTo.line();
|
||||
CommentInfo info = CommentInfo.create(
|
||||
CommentInfo createReply(CommentInfo replyTo) {
|
||||
return CommentInfo.create(
|
||||
path,
|
||||
side,
|
||||
line,
|
||||
replyTo.side(),
|
||||
replyTo.line(),
|
||||
replyTo.id(),
|
||||
initMessage);
|
||||
return addDraftBox(info, doSave);
|
||||
null);
|
||||
}
|
||||
|
||||
private DraftBox addDraftBox(CommentInfo info, boolean doSave) {
|
||||
DraftBox addDraftBox(CommentInfo info) {
|
||||
CodeMirror cm = getCmFromSide(info.side());
|
||||
DraftBox box = new DraftBox(this, cm, revision, info, commentLinkProcessor,
|
||||
true, doSave);
|
||||
DraftBox box = new DraftBox(this, cm, commentLinkProcessor, revision, info);
|
||||
addCommentBox(info, box);
|
||||
if (!doSave) {
|
||||
if (info.id() == null) {
|
||||
box.setOpen(true);
|
||||
box.setEdit(true);
|
||||
}
|
||||
LineHandle handle = cm.getLineHandle(info.line() - 1);
|
||||
@@ -560,9 +555,8 @@ public class SideBySide2 extends Screen {
|
||||
List<CommentInfo> sorted = sortComment(published);
|
||||
for (CommentInfo info : sorted) {
|
||||
CodeMirror cm = getCmFromSide(info.side());
|
||||
PublishedBox box =
|
||||
new PublishedBox(this, cm, revision, info, commentLinkProcessor);
|
||||
box.setOpen(false);
|
||||
PublishedBox box = new PublishedBox(this, commentLinkProcessor,
|
||||
revision, info);
|
||||
allBoxes.add(box);
|
||||
publishedMap.put(info.id(), box);
|
||||
int line = info.line() - 1;
|
||||
@@ -576,11 +570,9 @@ public class SideBySide2 extends Screen {
|
||||
private void renderDrafts() {
|
||||
List<CommentInfo> sorted = sortComment(drafts);
|
||||
for (CommentInfo info : sorted) {
|
||||
DraftBox box =
|
||||
new DraftBox(this, getCmFromSide(info.side()), revision, info,
|
||||
commentLinkProcessor, false, false);
|
||||
box.setOpen(false);
|
||||
box.setEdit(false);
|
||||
DraftBox box = new DraftBox(
|
||||
this, getCmFromSide(info.side()), commentLinkProcessor,
|
||||
revision, info);
|
||||
allBoxes.add(box);
|
||||
if (published != null) {
|
||||
PublishedBox replyToBox = publishedMap.get(info.in_reply_to());
|
||||
@@ -606,7 +598,7 @@ public class SideBySide2 extends Screen {
|
||||
for (CommentBox box : lineActiveBoxMap.values()) {
|
||||
List<SkippedLine> temp = new ArrayList<SkippedLine>();
|
||||
for (SkippedLine skip : skips) {
|
||||
CommentInfo info = box.getOriginal();
|
||||
CommentInfo info = box.getCommentInfo();
|
||||
int startLine = info.side() == Side.PARENT
|
||||
? skip.getStartA()
|
||||
: skip.getStartB();
|
||||
@@ -846,7 +838,7 @@ public class SideBySide2 extends Screen {
|
||||
CommentBox box = lineActiveBoxMap.get(handle);
|
||||
if (box == null) {
|
||||
lineActiveBoxMap.put(handle, addNewDraft(cm, line));
|
||||
} else if (box.isDraft()) {
|
||||
} else if (box instanceof DraftBox) {
|
||||
((DraftBox) lineActiveBoxMap.get(handle)).setEdit(true);
|
||||
} else {
|
||||
((PublishedBox) box).onReply(null);
|
||||
|
||||
Reference in New Issue
Block a user