InlineEdit: Implement CM3 integration, using new screen

Add new screen for editing file and commit message content and dispatch
to it when a user navigates to a file or commit message in change edit
mode from file table.

Two buttons are rendered in header of new edit screen: cancel and save.
Clicking on both of them takes user to CS2.

To differentiate between diff mode and edit mode in dispatcher, new
panel is used: ",edit"; "cm" is not used any more, as only CS2 is
supported:

  c/1/1/foo.txt

opens SBS2 screen, whereas

  c/1/1/foo.txt,edit

opens new edit screen with integrated CM3 editor.

Navigation in edit mode is harmonized from all places: file table and
SBS2 now using new edit screen to edit file and commit message content.
Edit file content popup dialog is only used in two places: When adding
new file to change edit or clicking on "Edit Message" button. In former
case this dialog is preserved until it is replaced by repository
browser. The usage of edit file icon in file table was dropped.

Change-Id: I4d70463357b82a8a3d675dd18b3ea5af99a434b0
This commit is contained in:
David Ostrovsky
2014-11-03 08:39:14 +01:00
parent b321f4d1ee
commit b2c9c2d69a
11 changed files with 326 additions and 207 deletions

View File

@@ -79,6 +79,7 @@ import com.google.gerrit.client.dashboards.DashboardList;
import com.google.gerrit.client.diff.DisplaySide;
import com.google.gerrit.client.diff.SideBySide2;
import com.google.gerrit.client.documentation.DocScreen;
import com.google.gerrit.client.editor.EditScreen;
import com.google.gerrit.client.groups.GroupApi;
import com.google.gerrit.client.groups.GroupInfo;
import com.google.gerrit.client.patches.PatchScreen;
@@ -169,6 +170,15 @@ public class Dispatcher {
}
}
public static String toEditScreen(PatchSet.Id revision, String fileName) {
Change.Id c = revision.getParentKey();
StringBuilder p = new StringBuilder();
p.append("/c/").append(c).append("/");
p.append(revision.getId()).append("/").append(KeyUtil.encode(fileName));
p.append(",edit");
return p.toString();
}
public static String toPublish(PatchSet.Id ps) {
Change.Id c = ps.getParentKey();
return "/c/" + c + "/" + ps.get() + ",publish";
@@ -735,6 +745,8 @@ public class Dispatcher {
patchTable,//
top,//
baseId);//
} else if (panel.equals("edit")) {
return new EditScreen(id);
}
}

View File

@@ -697,11 +697,9 @@ public class ChangeScreen2 extends Screen {
files.set(
b != null ? new PatchSet.Id(changeId, b._number()) : null,
new PatchSet.Id(changeId, rev._number()),
style, editMessage, reply, edit != null);
files.setValue(info.edit().files(), myLastReply(info),
emptyComment,
emptyComment,
fileTableMode);
style, editMessage, reply, fileTableMode, edit != null);
files.setValue(info.edit().files(), myLastReply(info), emptyComment,
emptyComment);
} else {
loadDiff(b, rev, myLastReply(info), group);
}
@@ -752,9 +750,8 @@ public class ChangeScreen2 extends Screen {
files.set(
base != null ? new PatchSet.Id(changeId, base._number()) : null,
new PatchSet.Id(changeId, rev._number()),
style, editMessage, reply, edit != null);
files.setValue(m, myLastReply, comments.get(0),
drafts.get(0), fileTableMode);
style, editMessage, reply, fileTableMode, edit != null);
files.setValue(m, myLastReply, comments.get(0), drafts.get(0));
}
@Override

View File

@@ -17,9 +17,9 @@ package com.google.gerrit.client.change;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.VoidResult;
import com.google.gerrit.client.changes.ChangeFileApi;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.TextBoxChangeListener;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
@@ -28,7 +28,6 @@ import com.google.gwt.event.dom.client.ClickEvent;
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.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
@@ -50,18 +49,6 @@ class EditFileBox extends Composite {
@UiField Button save;
@UiField Button cancel;
private AsyncCallback<VoidResult> cb = new AsyncCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult result) {
Gerrit.display(PageLinks.toChangeInEditMode(id.getParentKey()));
hide();
}
@Override
public void onFailure(Throwable caught) {
}
};
EditFileBox(
PatchSet.Id id,
String fileC,
@@ -94,11 +81,14 @@ class EditFileBox extends Composite {
@UiHandler("save")
void onSave(@SuppressWarnings("unused") ClickEvent e) {
if (Patch.COMMIT_MSG.equals(file.getText())) {
ChangeFileApi.putMessage(id, content.getText(), cb);
} else {
ChangeFileApi.putContent(id, file.getText(), content.getText(), cb);
}
ChangeFileApi.putContent(id, file.getText(), content.getText(),
new GerritCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult result) {
Gerrit.display(PageLinks.toChangeInEditMode(id.getParentKey()));
hide();
}
});
}
@UiHandler("cancel")

View File

@@ -25,7 +25,6 @@ import com.google.gerrit.client.changes.Util;
import com.google.gerrit.client.diff.FileInfo;
import com.google.gerrit.client.patches.PatchUtil;
import com.google.gerrit.client.rpc.CallbackGroup;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.rpc.RestApi;
@@ -87,19 +86,15 @@ public class FileTable extends FlowPanel {
String deltaColumn2();
String inserted();
String deleted();
String editButton();
String removeButton();
}
public static enum Mode {
REVIEW,
@SuppressWarnings("hiding")
EDIT
}
private static final String DELETE;
private static final String EDIT;
private static final String EDIT_MESSAGE;
private static final String RESTORE;
private static final String REVIEWED;
private static final String OPEN;
@@ -108,24 +103,16 @@ public class FileTable extends FlowPanel {
static {
DELETE = DOM.createUniqueId().replace('-', '_');
EDIT = DOM.createUniqueId().replace('-', '_');
EDIT_MESSAGE = DOM.createUniqueId().replace('-', '_');
RESTORE = DOM.createUniqueId().replace('-', '_');
REVIEWED = DOM.createUniqueId().replace('-', '_');
OPEN = DOM.createUniqueId().replace('-', '_');
init(DELETE, EDIT, EDIT_MESSAGE, RESTORE, REVIEWED, OPEN);
init(DELETE, RESTORE, REVIEWED, OPEN);
}
private static final native void init(String d, String e, String m, String t, String r, String o) /*-{
private static final native void init(String d, String t, String r, String o) /*-{
$wnd[d] = $entry(function(e,i) {
@com.google.gerrit.client.change.FileTable::onDelete(Lcom/google/gwt/dom/client/NativeEvent;I)(e,i)
});
$wnd[e] = $entry(function(e,i) {
@com.google.gerrit.client.change.FileTable::onEdit(Lcom/google/gwt/dom/client/NativeEvent;I)(e,i)
});
$wnd[m] = $entry(function(e,i) {
@com.google.gerrit.client.change.FileTable::onEditMessage(Lcom/google/gwt/dom/client/NativeEvent;I)(e,i)
});
$wnd[t] = $entry(function(e,i) {
@com.google.gerrit.client.change.FileTable::onRestore(Lcom/google/gwt/dom/client/NativeEvent;I)(e,i)
});
@@ -137,20 +124,6 @@ public class FileTable extends FlowPanel {
});
}-*/;
private static void onEdit(NativeEvent e, int idx) {
MyTable t = getMyTable(e);
if (t != null) {
t.onEdit(idx);
}
}
private static void onEditMessage(NativeEvent e, int idx) {
MyTable t = getMyTable(e);
if (t != null) {
t.onEditMessage(idx);
}
}
private static void onDelete(NativeEvent e, int idx) {
MyTable t = getMyTable(e);
if (t != null) {
@@ -206,6 +179,7 @@ public class FileTable extends FlowPanel {
private Widget editButton;
private Widget replyButton;
private boolean editExists;
private Mode mode;
@Override
protected void onLoad() {
@@ -214,25 +188,25 @@ public class FileTable extends FlowPanel {
}
public void set(PatchSet.Id base, PatchSet.Id curr, ChangeScreen2.Style style,
Widget editButton, Widget replyButton, boolean editExists) {
Widget editButton, Widget replyButton, Mode mode, boolean editExists) {
this.base = base;
this.curr = curr;
this.style = style;
this.editButton = editButton;
this.replyButton = replyButton;
this.mode = mode;
this.editExists = editExists;
}
void setValue(NativeMap<FileInfo> fileMap,
Timestamp myLastReply,
NativeMap<JsArray<CommentInfo>> comments,
NativeMap<JsArray<CommentInfo>> drafts,
Mode mode) {
NativeMap<JsArray<CommentInfo>> drafts) {
JsArray<FileInfo> list = fileMap.values();
FileInfo.sortFileInfoByPath(list);
DisplayCommand cmd = new DisplayCommand(fileMap, list,
myLastReply, comments, drafts, mode);
myLastReply, comments, drafts);
if (cmd.execute()) {
cmd.showProgressBar();
Scheduler.get().scheduleIncremental(cmd);
@@ -293,7 +267,9 @@ public class FileTable extends FlowPanel {
private String url(FileInfo info) {
return info.binary()
? Dispatcher.toUnified(base, curr, info.path())
: Dispatcher.toSideBySide(base, curr, info.path());
: mode == Mode.REVIEW
? Dispatcher.toSideBySide(base, curr, info.path())
: Dispatcher.toEditScreen(curr, info.path());
}
private final class MyTable extends NavigationTable<FileInfo> {
@@ -335,34 +311,6 @@ public class FileTable extends FlowPanel {
+ curr.toString());
}
void onEdit(int idx) {
final String path = list.get(idx).path();
final PatchSet.Id id = editExists && curr.get() != 0
? new PatchSet.Id(curr.getParentKey(), 0)
: curr;
ChangeFileApi.getContent(id, path,
new GerritCallback<String>() {
@Override
public void onSuccess(String result) {
EditFileAction edit = new EditFileAction(
id, result, path, style, editButton, replyButton);
edit.onEdit();
}
});
}
void onEditMessage(@SuppressWarnings("unused") int idx) {
ChangeFileApi.getMessage(curr,
new GerritCallback<String>() {
@Override
public void onSuccess(String r) {
EditFileAction edit = new EditFileAction(
curr, r, Patch.COMMIT_MSG, style, editButton, replyButton);
edit.onEdit();
}
});
}
void onDelete(int idx) {
String path = list.get(idx).path();
ChangeFileApi.deleteContent(curr, path,
@@ -491,7 +439,6 @@ public class FileTable extends FlowPanel {
private final NativeMap<JsArray<CommentInfo>> comments;
private final NativeMap<JsArray<CommentInfo>> drafts;
private final boolean hasUser;
private final Mode mode;
private boolean attached;
private int row;
private double start;
@@ -505,15 +452,13 @@ public class FileTable extends FlowPanel {
JsArray<FileInfo> list,
Timestamp myLastReply,
NativeMap<JsArray<CommentInfo>> comments,
NativeMap<JsArray<CommentInfo>> drafts,
Mode mode) {
NativeMap<JsArray<CommentInfo>> drafts) {
this.myTable = new MyTable(map, list);
this.list = list;
this.myLastReply = myLastReply;
this.comments = comments;
this.drafts = drafts;
this.hasUser = Gerrit.isSignedIn();
this.mode = mode;
myTable.addStyleName(R.css().table());
}
@@ -589,7 +534,6 @@ public class FileTable extends FlowPanel {
if (mode == Mode.REVIEW) {
sb.openTh().setStyleName(R.css().reviewed()).closeTh();
} else {
sb.openTh().setStyleName(R.css().editButton()).closeTh();
sb.openTh().setStyleName(R.css().removeButton()).closeTh();
}
sb.openTh().setStyleName(R.css().status()).closeTh();
@@ -611,7 +555,6 @@ public class FileTable extends FlowPanel {
if (mode == Mode.REVIEW) {
columnReviewed(sb, info);
} else {
columnEdit(sb, info);
columnDeleteRestore(sb, info);
}
columnStatus(sb, info);
@@ -638,28 +581,19 @@ public class FileTable extends FlowPanel {
sb.closeTd();
}
private void columnEdit(SafeHtmlBuilder sb, FileInfo info) {
sb.openTd().setStyleName(R.css().editButton());
if (hasUser && isEditable(info)) {
boolean m = Patch.COMMIT_MSG.equals(info.path());
sb.openElement("button")
.setAttribute("title",
m ? Resources.C.editMessage() : Resources.C.editFileInline())
.setAttribute("onclick",
(m ? EDIT_MESSAGE : EDIT) + "(event," + info._row() + ")")
.append(new ImageResourceRenderer().render(Gerrit.RESOURCES.edit()))
.closeElement("button");
}
sb.closeTd();
}
private void columnPathEdit(SafeHtmlBuilder sb, FileInfo info) {
sb.openTd().setStyleName(R.css().pathColumn());
String path = info.path();
sb.openAnchor();
if (!isEditable(info)) {
sb.setAttribute("onclick", RESTORE + "(event," + info._row() + ")");
} else {
sb.setAttribute("href", "#" + url(info))
.setAttribute("onclick", OPEN + "(event," + info._row()
+ ")");
}
if (!Patch.COMMIT_MSG.equals(path)) {
sb.openAnchor()
.setAttribute("onclick", (isEditable(info) ? EDIT : RESTORE)
+ "(event," + info._row() + ")");
int commonPrefixLen = commonPrefix(path);
if (commonPrefixLen > 0) {
sb.openSpan().setStyleName(R.css().commonPrefix())
@@ -667,10 +601,10 @@ public class FileTable extends FlowPanel {
.closeSpan();
}
sb.append(path.substring(commonPrefixLen));
sb.closeAnchor();
} else {
sb.append(Util.C.commitMessage());
}
sb.closeAnchor();
sb.closeTd();
}
@@ -845,8 +779,7 @@ public class FileTable extends FlowPanel {
if (mode == Mode.REVIEW) {
sb.openTh().setStyleName(R.css().reviewed()).closeTh();
} else {
sb.openTh().setStyleName(R.css().editButton()).closeTh();
sb.openTh().setStyleName(R.css().editButton()).closeTh();
sb.openTh().setStyleName(R.css().removeButton()).closeTh();
}
sb.openTh().setStyleName(R.css().status()).closeTh();
sb.openTd().closeTd(); // path

View File

@@ -86,15 +86,6 @@
background-color: #d44;
}
.editButton button {
cursor: pointer;
padding: 0;
margin: 0 0 0 5px;
border: 0;
background-color: transparent;
white-space: nowrap;
}
.removeButton button {
cursor: pointer;
padding: 0;

View File

@@ -15,9 +15,11 @@
package com.google.gerrit.client.changes;
import com.google.gerrit.client.VoidResult;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.NativeString;
import com.google.gerrit.client.rpc.RestApi;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -67,21 +69,44 @@ public class ChangeFileApi {
wrapper(cb));
}
/**
* Get the contents of a file or commit message in a PatchSet or change
* edit.
**/
public static void getContentOrMessage(PatchSet.Id id, String path,
AsyncCallback<String> cb) {
if (Patch.COMMIT_MSG.equals(path)) {
getMessage(id, cb);
} else {
contentEditOrPs(id, path).get(wrapper(cb));
}
}
/** Put contents into a File in a change edit. */
public static void putContent(PatchSet.Id id, String filename,
String content, AsyncCallback<VoidResult> result) {
String content, GerritCallback<VoidResult> result) {
contentEdit(id.getParentKey(), filename).put(content, result);
}
/** Put contents into a File or commit message in a change edit. */
public static void putContentOrMessage(PatchSet.Id id, String path,
String content, GerritCallback<VoidResult> result) {
if (Patch.COMMIT_MSG.equals(path)) {
putMessage(id, content, result);
} else {
contentEdit(id.getParentKey(), path).put(content, result);
}
}
/** Put message into a change edit. */
public static void putMessage(PatchSet.Id id, String m,
AsyncCallback<VoidResult> r) {
private static void putMessage(PatchSet.Id id, String m,
GerritCallback<VoidResult> r) {
putMessage(id.getParentKey(), m, r);
}
/** Put message into a change edit. */
public static void putMessage(Change.Id id, String m,
AsyncCallback<VoidResult> r) {
GerritCallback<VoidResult> r) {
ChangeApi.change(id.get()).view("edit:message").put(m, r);
}

View File

@@ -16,12 +16,9 @@ package com.google.gerrit.client.diff;
import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.VoidResult;
import com.google.gerrit.client.WebLinkInfo;
import com.google.gerrit.client.changes.ChangeFileApi;
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
import com.google.gerrit.client.patches.PatchUtil;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.ui.InlineHyperlink;
import com.google.gerrit.reviewdb.client.Change;
@@ -30,7 +27,6 @@ import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
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;
@@ -114,8 +110,7 @@ class PatchSetSelectBox2 extends Composite {
if (!Patch.COMMIT_MSG.equals(path)) {
linkPanel.add(createDownloadLink());
}
if (open && idActive != null && Gerrit.isSignedIn()
&& !Patch.COMMIT_MSG.equals(path)) {
if (open && idActive != null && Gerrit.isSignedIn()) {
if ((editExists && idActive.get() == 0)
|| (!editExists && idActive.get() == currentPatchSet)) {
linkPanel.add(createEditIcon());
@@ -130,37 +125,10 @@ class PatchSetSelectBox2 extends Composite {
}
private Widget createEditIcon() {
final Anchor anchor = new Anchor(
new ImageResourceRenderer().render(Gerrit.RESOURCES.edit()));
anchor.addClickHandler(new ClickHandler() {
boolean editing = false;
@Override
public void onClick(ClickEvent event) {
final PatchSet.Id id = (idActive == null) ? other.idActive : idActive;
editing = !editing;
parent.editSideB(editing);
if (editing) {
ChangeFileApi.getContent(id, path,
new GerritCallback<String>() {
@Override
public void onSuccess(String content) {
parent.setSideBContent(content);
}
});
anchor.setHTML(new ImageResourceRenderer().render(Gerrit.RESOURCES.save()));
} else {
anchor.setHTML(new ImageResourceRenderer().render(Gerrit.RESOURCES.edit()));
String siteBContent = parent.getSideBContent();
ChangeFileApi.putContent(id, path, siteBContent,
new GerritCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult result) {
}
});
}
}
});
PatchSet.Id id = (idActive == null) ? other.idActive : idActive;
Anchor anchor = new Anchor(
new ImageResourceRenderer().render(Gerrit.RESOURCES.edit()),
"#" + Dispatcher.toEditScreen(id, path));
anchor.setTitle(PatchUtil.C.edit());
return anchor;
}

View File

@@ -138,8 +138,6 @@ public class SideBySide2 extends Screen {
private List<HandlerRegistration> handlers;
private PreferencesAction prefsAction;
private int reloadVersionId;
private KeyMap sbsKeyMap;
private boolean isEdited = false;
public SideBySide2(
PatchSet.Id base,
@@ -349,7 +347,7 @@ public class SideBySide2 extends Screen {
cm.on("cursorActivity", updateActiveLine(cm));
cm.on("gutterClick", onGutterClick(cm));
cm.on("focus", updateActiveLine(cm));
sbsKeyMap = KeyMap.create()
cm.addKeyMap(KeyMap.create()
.on("A", upToChange(true))
.on("U", upToChange(false))
.on("[", header.navigate(Direction.PREV))
@@ -415,8 +413,7 @@ public class SideBySide2 extends Screen {
public void run() {
cm.execCommand("selectAll");
}
});
cm.addKeyMap(sbsKeyMap);
}));
if (prefs.renderEntireFile()) {
cm.addKeyMap(RENDER_ENTIRE_FILE_KEYMAP);
}
@@ -428,9 +425,6 @@ public class SideBySide2 extends Screen {
@Override
public void handle(CodeMirror cm, LineCharacter anchor, LineCharacter head) {
if (isEdited) {
return;
}
if (anchor == head
|| (anchor.getLine() == head.getLine()
&& anchor.getCh() == head.getCh())) {
@@ -549,30 +543,6 @@ public class SideBySide2 extends Screen {
}));
}
public void editSideB(boolean state) {
isEdited = state;
cmB.setOption("readOnly", !state);
JumpKeys.enable(!state);
if (state) {
removeKeyHandlerRegistrations();
cmB.removeKeyMap(sbsKeyMap);
cmB.setOption("keyMap", "default");
cmB.focus();
} else {
cmB.setOption("keyMap", "vim_ro");
cmB.addKeyMap(sbsKeyMap);
registerKeys();
}
}
public String getSideBContent() {
return cmB.getValue();
}
public void setSideBContent(String content) {
cmB.setValue(content);
}
private void display(final CommentsCollections comments) {
setThemeStyles(prefs.theme().isDark());
setShowTabs(prefs.showTabs());

View File

@@ -0,0 +1,134 @@
// Copyright (C) 2014 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.editor;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.VoidResult;
import com.google.gerrit.client.changes.ChangeFileApi;
import com.google.gerrit.client.rpc.CallbackGroup;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.reviewdb.client.Patch;
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.KeyPressEvent;
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.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwtexpui.globalkey.client.GlobalKey;
import net.codemirror.lib.CodeMirror;
import net.codemirror.lib.Configuration;
public class EditScreen extends Screen {
interface Binder extends UiBinder<HTMLPanel, EditScreen> {}
private static final Binder uiBinder = GWT.create(Binder.class);
private final PatchSet.Id revision;
private final String path;
private CodeMirror cm;
@UiField Element filePath;
@UiField Button cancel;
@UiField Button save;
@UiField Element editor;
public EditScreen(Patch.Key patch) {
this.revision = patch.getParentKey();
this.path = patch.get();
add(uiBinder.createAndBindUi(this));
addDomHandler(GlobalKey.STOP_PROPAGATION, KeyPressEvent.getType());
}
@Override
protected void onInitUI() {
super.onInitUI();
setHeaderVisible(false);
}
@Override
protected void onLoad() {
super.onLoad();
CallbackGroup cmGroup = new CallbackGroup();
CodeMirror.initLibrary(cmGroup.add(CallbackGroup.<Void> emptyCallback()));
initPath();
ChangeFileApi.getContentOrMessage(revision, path,
cmGroup.addFinal(new ScreenLoadCallback<String>(this) {
@Override
protected void preDisplay(String content) {
initEditor(content);
}
}));
}
@Override
public void onShowView() {
super.onShowView();
int rest = Gerrit.getHeaderFooterHeight()
+ 30; // Estimate
cm.setHeight(Window.getClientHeight() - rest);
cm.refresh();
cm.focus();
}
@UiHandler("save")
void onSave(@SuppressWarnings("unused") ClickEvent e) {
ChangeFileApi.putContentOrMessage(revision, path, cm.getValue(),
new GerritCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult result) {
Gerrit.display(PageLinks.toChangeInEditMode(
revision.getParentKey()));
}
});
}
@UiHandler("cancel")
void onCancel(@SuppressWarnings("unused") ClickEvent e) {
Gerrit.display(PageLinks.toChangeInEditMode(revision.getParentKey()));
}
private void initEditor(String content) {
cm = CodeMirror.create(editor, getConfig());
cm.setValue(content);
}
private Configuration getConfig() {
// TODO(davido): Retrieve user preferences from AllUsers repository
// TODO(davido): Retrieve file content type to activate syntax highlighting
return Configuration.create()
.set("readOnly", false)
.set("cursorBlinkRate", 0)
.set("cursorHeight", 0.85)
.set("lineNumbers", true)
.set("tabSize", 4)
.set("lineWrapping", false)
.set("styleSelectedText", true)
.set("showTrailingSpace", true)
.set("keyMap", "default");
}
private void initPath() {
filePath.setInnerText(path);
}
}

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2014 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:e='urn:import:com.google.gerrit.client.editor'>
<ui:style>
@eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
@def HEADER_HEIGHT 30px;
@def BUTTON_HEIGHT 14px;
.infoLine {
position: absolute;
top: 0;
left: 10px;
height: HEADER_HEIGHT;
padding-left: 25px;
}
.headerLine {
position: relative;
background-color: trimColor;
height: HEADER_HEIGHT;
margin: 0 -5px;
padding: 0 5px;
}
.headerButtons button:disabled,
#change_infoTable button:disabled,
.popdown button:disabled {
background-color: #999;
}
.headerButtons button {
margin: 6px 3px 0 0;
text-align: center;
font-size: 8pt;
font-weight: bold;
cursor: pointer;
border: 2px solid;
color: rgba(0, 0, 0, 0.15);
background-color: #f5f5f5;
-webkit-border-radius: 2px;
-webkit-box-sizing: content-box;
}
.headerButtons button div {
color: #444;
min-width: 54px;
white-space: nowrap;
height: BUTTON_HEIGHT;
line-height: BUTTON_HEIGHT;
}
.infoLineHeaderButtons {
display: inline-block;
height: HEADER_HEIGHT;
line-height: HEADER_HEIGHT;
vertical-align: top;
}
.path {
white-space: nowrap;
}
</ui:style>
<g:HTMLPanel>
<g:HTMLPanel styleName='{style.headerLine}'>
<div class='{style.infoLine}'>
<div class='{style.headerButtons} {style.infoLineHeaderButtons}'>
<g:Button ui:field='cancel'
styleName=''
title='Cancel'>
<ui:attribute name='title'/>
<div><ui:msg>Cancel</ui:msg></div>
</g:Button>
<g:Button ui:field='save'
styleName=''
title='Save'>
<ui:attribute name='title'/>
<div><ui:msg>Save</ui:msg></div>
</g:Button>
|
<span class='{style.path}' ui:field='filePath'/>
</div>
</div>
</g:HTMLPanel>
<div ui:field='editor' />
</g:HTMLPanel>
</ui:UiBinder>

View File

@@ -41,6 +41,10 @@ public class CodeMirror extends JavaScriptObject {
return m;
}-*/;
public static CodeMirror create(Element parent, Configuration cfg) {
return create(null, parent, cfg);
}
public final native void setOption(String option, boolean value) /*-{
this.setOption(option, value);
}-*/;
@@ -95,15 +99,7 @@ public class CodeMirror extends JavaScriptObject {
private final native void addLineClassNative(LineHandle line, String where,
String lineClass) /*-{
try {
this.addLineClass(line, where, lineClass);
} catch (err) {
if ("TypeError: Cannot read property 'parrent' of undefinded" == err.toString()) {
// ignore CodeMirror bug after going to new line
return;
}
throw err;
}
this.addLineClass(line, where, lineClass);
}-*/;
public final void removeLineClass(int line, LineClassWhere where,