InlineEdit: Allow to save/load user preferences in Codemirror
Change-Id: Ice334364cdb952eaa93118362c438dcc291db2af
This commit is contained in:
parent
0ca0182ab8
commit
8018fbbc1e
@ -154,11 +154,6 @@ Alternatively change edits can be accessed through "My => Edits" dashboard.
|
|||||||
[[not-implemented-features]]
|
[[not-implemented-features]]
|
||||||
== Not Implemented Features
|
== Not Implemented Features
|
||||||
|
|
||||||
* [PENDING CHANGE]
|
|
||||||
The inline editor uses settings decided from the user's diff preferences, but those
|
|
||||||
preferences are only modifiable from the side-by-side diff screen. It should be possible
|
|
||||||
to open the preferences also from within the editor.
|
|
||||||
|
|
||||||
* Support default configuration options for inline editor that an
|
* Support default configuration options for inline editor that an
|
||||||
administrator has set in `refs/users/default:preferences.config` file.
|
administrator has set in `refs/users/default:preferences.config` file.
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ import com.google.gerrit.client.ui.Screen;
|
|||||||
import com.google.gerrit.common.PageLinks;
|
import com.google.gerrit.common.PageLinks;
|
||||||
import com.google.gerrit.common.data.HostPageData;
|
import com.google.gerrit.common.data.HostPageData;
|
||||||
import com.google.gerrit.common.data.SystemInfoService;
|
import com.google.gerrit.common.data.SystemInfoService;
|
||||||
|
import com.google.gerrit.extensions.client.EditPreferencesInfo;
|
||||||
import com.google.gerrit.extensions.client.GerritTopMenu;
|
import com.google.gerrit.extensions.client.GerritTopMenu;
|
||||||
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
|
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
@ -118,6 +119,7 @@ public class Gerrit implements EntryPoint {
|
|||||||
private static HostPageData.Theme myTheme;
|
private static HostPageData.Theme myTheme;
|
||||||
private static String defaultScreenToken;
|
private static String defaultScreenToken;
|
||||||
private static AccountDiffPreference myAccountDiffPref;
|
private static AccountDiffPreference myAccountDiffPref;
|
||||||
|
private static EditPreferencesInfo editPrefs;
|
||||||
private static String xGerritAuth;
|
private static String xGerritAuth;
|
||||||
private static boolean isNoteDbEnabled;
|
private static boolean isNoteDbEnabled;
|
||||||
|
|
||||||
@ -327,6 +329,14 @@ public class Gerrit implements EntryPoint {
|
|||||||
myAccountDiffPref = accountDiffPref;
|
myAccountDiffPref = accountDiffPref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static EditPreferencesInfo getEditPreferences() {
|
||||||
|
return editPrefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setEditPreferences(EditPreferencesInfo p) {
|
||||||
|
editPrefs = p;
|
||||||
|
}
|
||||||
|
|
||||||
/** @return true if the user is currently authenticated */
|
/** @return true if the user is currently authenticated */
|
||||||
public static boolean isSignedIn() {
|
public static boolean isSignedIn() {
|
||||||
return xGerritAuth != null;
|
return xGerritAuth != null;
|
||||||
|
@ -37,6 +37,17 @@ public class AccountApi {
|
|||||||
return new RestApi("/accounts/").view("self");
|
return new RestApi("/accounts/").view("self");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Retrieve the account edit preferences */
|
||||||
|
public static void getEditPreferences(AsyncCallback<EditPreferences> cb) {
|
||||||
|
self().view("preferences.edit").get(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Put the account edit preferences */
|
||||||
|
public static void putEditPreferences(EditPreferences in,
|
||||||
|
AsyncCallback<VoidResult> cb) {
|
||||||
|
self().view("preferences.edit").put(in, cb);
|
||||||
|
}
|
||||||
|
|
||||||
public static void suggest(String query, int limit,
|
public static void suggest(String query, int limit,
|
||||||
AsyncCallback<JsArray<AccountInfo>> cb) {
|
AsyncCallback<JsArray<AccountInfo>> cb) {
|
||||||
new RestApi("/accounts/")
|
new RestApi("/accounts/")
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
// 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.account;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.client.EditPreferencesInfo;
|
||||||
|
import com.google.gerrit.extensions.client.Theme;
|
||||||
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
|
|
||||||
|
public class EditPreferences extends JavaScriptObject {
|
||||||
|
public static EditPreferences create(EditPreferencesInfo in) {
|
||||||
|
EditPreferences p = createObject().cast();
|
||||||
|
p.tabSize(in.tabSize);
|
||||||
|
p.lineLength(in.lineLength);
|
||||||
|
p.hideTopMenu(in.hideTopMenu);
|
||||||
|
p.showTabs(in.showTabs);
|
||||||
|
p.showWhitespaceErrors(in.showWhitespaceErrors);
|
||||||
|
p.syntaxHighlighting(in.syntaxHighlighting);
|
||||||
|
p.hideLineNumbers(in.hideLineNumbers);
|
||||||
|
p.theme(in.theme);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void copyTo(EditPreferencesInfo p) {
|
||||||
|
p.tabSize = tabSize();
|
||||||
|
p.lineLength = lineLength();
|
||||||
|
p.hideTopMenu = hideTopMenu();
|
||||||
|
p.showTabs = showTabs();
|
||||||
|
p.showWhitespaceErrors = showWhitespaceErrors();
|
||||||
|
p.syntaxHighlighting = syntaxHighlighting();
|
||||||
|
p.hideLineNumbers = hideLineNumbers();
|
||||||
|
p.theme = theme();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void theme(Theme i) {
|
||||||
|
setThemeRaw(i != null ? i.toString() : Theme.DEFAULT.toString());
|
||||||
|
}
|
||||||
|
private final native void setThemeRaw(String i) /*-{ this.theme = i }-*/;
|
||||||
|
|
||||||
|
public final native void tabSize(int t) /*-{ this.tab_size = t }-*/;
|
||||||
|
public final native void lineLength(int c) /*-{ this.line_length = c }-*/;
|
||||||
|
public final native void hideTopMenu(boolean s) /*-{ this.hide_top_menu = s }-*/;
|
||||||
|
public final native void showTabs(boolean s) /*-{ this.show_tabs = s }-*/;
|
||||||
|
public final native void showWhitespaceErrors(boolean s) /*-{ this.show_whitespace_errors = s }-*/;
|
||||||
|
public final native void syntaxHighlighting(boolean s) /*-{ this.syntax_highlighting = s }-*/;
|
||||||
|
public final native void hideLineNumbers(boolean s) /*-{ this.hide_line_numbers = s }-*/;
|
||||||
|
|
||||||
|
public final Theme theme() {
|
||||||
|
String s = themeRaw();
|
||||||
|
return s != null ? Theme.valueOf(s) : Theme.DEFAULT;
|
||||||
|
}
|
||||||
|
private final native String themeRaw() /*-{ return this.theme }-*/;
|
||||||
|
|
||||||
|
public final int tabSize() {return get("tab_size", 8); }
|
||||||
|
public final int lineLength() {return get("line_length", 100); }
|
||||||
|
public final native boolean hideTopMenu() /*-{ return this.hide_top_menu || false }-*/;
|
||||||
|
public final native boolean showTabs() /*-{ return this.show_tabs || false }-*/;
|
||||||
|
public final native boolean showWhitespaceErrors() /*-{ return this.show_whitespace_errors || false }-*/;
|
||||||
|
public final native boolean syntaxHighlighting() /*-{ return this.syntax_highlighting || false }-*/;
|
||||||
|
public final native boolean hideLineNumbers() /*-{ return this.hide_line_numbers || false }-*/;
|
||||||
|
private final native int get(String n, int d) /*-{ return this.hasOwnProperty(n) ? this[n] : d }-*/;
|
||||||
|
|
||||||
|
protected EditPreferences() {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
// 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.account.EditPreferences;
|
||||||
|
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||||
|
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||||
|
import com.google.gwt.user.client.ui.PopupPanel;
|
||||||
|
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
|
||||||
|
|
||||||
|
class EditPreferencesAction {
|
||||||
|
private final EditScreen view;
|
||||||
|
private final EditPreferences prefs;
|
||||||
|
private PopupPanel popup;
|
||||||
|
private EditPreferencesBox current;
|
||||||
|
|
||||||
|
EditPreferencesAction(EditScreen view, EditPreferences prefs) {
|
||||||
|
this.view = view;
|
||||||
|
this.prefs = prefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void show() {
|
||||||
|
if (popup != null) {
|
||||||
|
hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = new EditPreferencesBox(view);
|
||||||
|
current.set(prefs);
|
||||||
|
|
||||||
|
popup = new PopupPanel(true, false);
|
||||||
|
popup.setStyleName(current.style.dialog());
|
||||||
|
popup.add(current);
|
||||||
|
popup.addCloseHandler(new CloseHandler<PopupPanel>() {
|
||||||
|
@Override
|
||||||
|
public void onClose(CloseEvent<PopupPanel> event) {
|
||||||
|
view.getEditor().focus();
|
||||||
|
popup = null;
|
||||||
|
current = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
popup.setPopupPositionAndShow(new PositionCallback() {
|
||||||
|
@Override
|
||||||
|
public void setPosition(int offsetWidth, int offsetHeight) {
|
||||||
|
popup.setPopupPosition(300, 120);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void hide() {
|
||||||
|
if (popup != null) {
|
||||||
|
popup.hide();
|
||||||
|
popup = null;
|
||||||
|
current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,213 @@
|
|||||||
|
// 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.account.AccountApi;
|
||||||
|
import com.google.gerrit.client.account.EditPreferences;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.client.ui.NpIntTextBox;
|
||||||
|
import com.google.gerrit.extensions.client.Theme;
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.event.dom.client.ChangeEvent;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||||
|
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.Anchor;
|
||||||
|
import com.google.gwt.user.client.ui.Button;
|
||||||
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
|
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||||
|
import com.google.gwt.user.client.ui.ListBox;
|
||||||
|
import com.google.gwt.user.client.ui.PopupPanel;
|
||||||
|
import com.google.gwt.user.client.ui.ToggleButton;
|
||||||
|
|
||||||
|
import net.codemirror.theme.ThemeLoader;
|
||||||
|
|
||||||
|
/** Displays current edit preferences. */
|
||||||
|
class EditPreferencesBox extends Composite {
|
||||||
|
interface Binder extends UiBinder<HTMLPanel, EditPreferencesBox> {}
|
||||||
|
private static final Binder uiBinder = GWT.create(Binder.class);
|
||||||
|
|
||||||
|
interface Style extends CssResource {
|
||||||
|
String dialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final EditScreen view;
|
||||||
|
private EditPreferences prefs;
|
||||||
|
|
||||||
|
@UiField Style style;
|
||||||
|
@UiField Anchor close;
|
||||||
|
@UiField NpIntTextBox tabWidth;
|
||||||
|
@UiField NpIntTextBox lineLength;
|
||||||
|
@UiField ToggleButton topMenu;
|
||||||
|
@UiField ToggleButton syntaxHighlighting;
|
||||||
|
@UiField ToggleButton showTabs;
|
||||||
|
@UiField ToggleButton whitespaceErrors;
|
||||||
|
@UiField ToggleButton lineNumbers;
|
||||||
|
@UiField ListBox theme;
|
||||||
|
@UiField Button apply;
|
||||||
|
@UiField Button save;
|
||||||
|
|
||||||
|
EditPreferencesBox(EditScreen view) {
|
||||||
|
this.view = view;
|
||||||
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
initTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(EditPreferences prefs) {
|
||||||
|
this.prefs = prefs;
|
||||||
|
|
||||||
|
tabWidth.setIntValue(prefs.tabSize());
|
||||||
|
lineLength.setIntValue(prefs.lineLength());
|
||||||
|
topMenu.setValue(!prefs.hideTopMenu());
|
||||||
|
syntaxHighlighting.setValue(prefs.syntaxHighlighting());
|
||||||
|
showTabs.setValue(prefs.showTabs());
|
||||||
|
whitespaceErrors.setValue(prefs.showWhitespaceErrors());
|
||||||
|
lineNumbers.setValue(prefs.hideLineNumbers());
|
||||||
|
setTheme(prefs.theme());
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("tabWidth")
|
||||||
|
void onTabWidth(ValueChangeEvent<String> e) {
|
||||||
|
String v = e.getValue();
|
||||||
|
if (v != null && v.length() > 0) {
|
||||||
|
prefs.tabSize(Math.max(1, Integer.parseInt(v)));
|
||||||
|
view.getEditor().setOption("tabSize", v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("lineLength")
|
||||||
|
void onLineLength(ValueChangeEvent<String> e) {
|
||||||
|
String v = e.getValue();
|
||||||
|
if (v != null && v.length() > 0) {
|
||||||
|
prefs.lineLength(Math.max(1, Integer.parseInt(v)));
|
||||||
|
view.setLineLength(prefs.lineLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("topMenu")
|
||||||
|
void onTopMenu(ValueChangeEvent<Boolean> e) {
|
||||||
|
prefs.hideTopMenu(!e.getValue());
|
||||||
|
Gerrit.setHeaderVisible(!prefs.hideTopMenu());
|
||||||
|
view.resizeCodeMirror();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("showTabs")
|
||||||
|
void onShowTabs(ValueChangeEvent<Boolean> e) {
|
||||||
|
prefs.showTabs(e.getValue());
|
||||||
|
view.setShowTabs(prefs.showTabs());
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("whitespaceErrors")
|
||||||
|
void onshowTrailingSpace(ValueChangeEvent<Boolean> e) {
|
||||||
|
prefs.showWhitespaceErrors(e.getValue());
|
||||||
|
view.setShowWhitespaceErrors(prefs.showWhitespaceErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("lineNumbers")
|
||||||
|
void onLineNumbers(ValueChangeEvent<Boolean> e) {
|
||||||
|
prefs.hideLineNumbers(e.getValue());
|
||||||
|
view.setShowLineNumbers(prefs.hideLineNumbers());
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("syntaxHighlighting")
|
||||||
|
void onSyntaxHighlighting(ValueChangeEvent<Boolean> e) {
|
||||||
|
prefs.syntaxHighlighting(e.getValue());
|
||||||
|
view.setSyntaxHighlighting(prefs.syntaxHighlighting());
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("theme")
|
||||||
|
void onTheme(@SuppressWarnings("unused") ChangeEvent e) {
|
||||||
|
final Theme newTheme = Theme.valueOf(theme.getValue(theme.getSelectedIndex()));
|
||||||
|
prefs.theme(newTheme);
|
||||||
|
ThemeLoader.loadTheme(newTheme, new GerritCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Void result) {
|
||||||
|
view.getEditor().operation(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
String t = newTheme.name().toLowerCase();
|
||||||
|
view.getEditor().setOption("theme", t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("apply")
|
||||||
|
void onApply(@SuppressWarnings("unused") ClickEvent e) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("save")
|
||||||
|
void onSave(@SuppressWarnings("unused") ClickEvent e) {
|
||||||
|
AccountApi.putEditPreferences(prefs, new GerritCallback<VoidResult>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(VoidResult n) {
|
||||||
|
prefs.copyTo(Gerrit.getEditPreferences());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("close")
|
||||||
|
void onClose(ClickEvent e) {
|
||||||
|
e.preventDefault();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close() {
|
||||||
|
((PopupPanel) getParent()).hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTheme(Theme v) {
|
||||||
|
String name = v != null ? v.name() : Theme.DEFAULT.name();
|
||||||
|
for (int i = 0; i < theme.getItemCount(); i++) {
|
||||||
|
if (theme.getValue(i).equals(name)) {
|
||||||
|
theme.setSelectedIndex(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
theme.setSelectedIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initTheme() {
|
||||||
|
theme.addItem(
|
||||||
|
Theme.DEFAULT.name().toLowerCase(),
|
||||||
|
Theme.DEFAULT.name());
|
||||||
|
theme.addItem(
|
||||||
|
Theme.ECLIPSE.name().toLowerCase(),
|
||||||
|
Theme.ECLIPSE.name());
|
||||||
|
theme.addItem(
|
||||||
|
Theme.ELEGANT.name().toLowerCase(),
|
||||||
|
Theme.ELEGANT.name());
|
||||||
|
theme.addItem(
|
||||||
|
Theme.NEAT.name().toLowerCase(),
|
||||||
|
Theme.NEAT.name());
|
||||||
|
theme.addItem(
|
||||||
|
Theme.MIDNIGHT.name().toLowerCase(),
|
||||||
|
Theme.MIDNIGHT.name());
|
||||||
|
theme.addItem(
|
||||||
|
Theme.NIGHT.name().toLowerCase(),
|
||||||
|
Theme.NIGHT.name());
|
||||||
|
theme.addItem(
|
||||||
|
Theme.TWILIGHT.name().toLowerCase(),
|
||||||
|
Theme.TWILIGHT.name());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,228 @@
|
|||||||
|
<?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:x='urn:import:com.google.gerrit.client.ui'>
|
||||||
|
<ui:style type='com.google.gerrit.client.editor.EditPreferencesBox.Style'>
|
||||||
|
@external .gwt-TextBox;
|
||||||
|
@external .gwt-ToggleButton .html-face;
|
||||||
|
@external .gwt-ToggleButton-up;
|
||||||
|
@external .gwt-ToggleButton-up-hovering;
|
||||||
|
@external .gwt-ToggleButton-up-disabled;
|
||||||
|
@external .gwt-ToggleButton-down;
|
||||||
|
@external .gwt-ToggleButton-down-hovering;
|
||||||
|
@external .gwt-ToggleButton-down-disabled;
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
background: rgba(0, 0, 0, 0.85) none repeat scroll 0 50%;
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: arial,sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: left;
|
||||||
|
text-shadow: 1px 1px 7px #000000;
|
||||||
|
min-width: 300px;
|
||||||
|
z-index: 200;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@if user.agent safari {
|
||||||
|
.dialog {
|
||||||
|
\-webkit-border-radius: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if user.agent gecko1_8 {
|
||||||
|
.dialog {
|
||||||
|
\-moz-border-radius: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.box { margin: 10px; }
|
||||||
|
.box .gwt-TextBox { padding: 0; }
|
||||||
|
.context { vertical-align: bottom; }
|
||||||
|
|
||||||
|
.table tr { min-height: 23px; }
|
||||||
|
.table th,
|
||||||
|
.table td {
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
padding-right: 8px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box a,
|
||||||
|
.box a:visited,
|
||||||
|
.box a:hover {
|
||||||
|
color: #dddd00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .gwt-ToggleButton {
|
||||||
|
position: relative;
|
||||||
|
height: 19px;
|
||||||
|
width: 140px;
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
.box .gwt-ToggleButton .html-face {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 68px;
|
||||||
|
height: 17px;
|
||||||
|
line-height: 17px;
|
||||||
|
text-align: center;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .gwt-ToggleButton-up,
|
||||||
|
.box .gwt-ToggleButton-up-hovering,
|
||||||
|
.box .gwt-ToggleButton-up-disabled,
|
||||||
|
.box .gwt-ToggleButton-down,
|
||||||
|
.box .gwt-ToggleButton-down-hovering,
|
||||||
|
.box .gwt-ToggleButton-down-disabled {
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.box .gwt-ToggleButton-up .html-face,
|
||||||
|
.box .gwt-ToggleButton-up-hovering .html-face {
|
||||||
|
left: 0;
|
||||||
|
background: #cacaca;
|
||||||
|
border-style: outset;
|
||||||
|
}
|
||||||
|
.box .gwt-ToggleButton-down .html-face,
|
||||||
|
.box .gwt-ToggleButton-down-hovering .html-face {
|
||||||
|
right: 0;
|
||||||
|
background: #bcf;
|
||||||
|
border-style: inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box button {
|
||||||
|
margin: 6px 3px 0 0;
|
||||||
|
border-color: rgba(0, 0, 0, 0.1);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 8pt;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 1px solid;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #444;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
|
||||||
|
-webkit-border-radius: 2px;
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
}
|
||||||
|
.box button div {
|
||||||
|
color: #444;
|
||||||
|
height: 10px;
|
||||||
|
min-width: 54px;
|
||||||
|
line-height: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.apply {
|
||||||
|
background-color: #4d90fe;
|
||||||
|
background-image: -webkit-linear-gradient(top, #4d90fe, #4d90fe);
|
||||||
|
}
|
||||||
|
button.apply div { color: #fff; }
|
||||||
|
|
||||||
|
button.save {
|
||||||
|
margin-left: 10px;
|
||||||
|
color: #d14836;
|
||||||
|
background-color: #d14836;
|
||||||
|
background-image: -webkit-linear-gradient(top, #d14836, #d14836);
|
||||||
|
}
|
||||||
|
button.save div { color: #fff; }
|
||||||
|
</ui:style>
|
||||||
|
|
||||||
|
<g:HTMLPanel styleName='{style.box}'>
|
||||||
|
<table style='width: 100%'>
|
||||||
|
<tr>
|
||||||
|
<td><ui:msg>Edit Preferences</ui:msg></td>
|
||||||
|
<td style='text-align: right'>
|
||||||
|
<g:Anchor ui:field='close' href='javascript:;'><ui:msg>Close</ui:msg></g:Anchor>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr/>
|
||||||
|
<table class='{style.table}'>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Theme</ui:msg></th>
|
||||||
|
<td><g:ListBox ui:field='theme'/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Tab Width</ui:msg></th>
|
||||||
|
<td><x:NpIntTextBox ui:field='tabWidth'
|
||||||
|
visibleLength='4'
|
||||||
|
alignment='RIGHT'/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Columns</ui:msg></th>
|
||||||
|
<td><x:NpIntTextBox ui:field='lineLength'
|
||||||
|
visibleLength='4'
|
||||||
|
alignment='RIGHT'/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Top Menu</ui:msg></th>
|
||||||
|
<td><g:ToggleButton ui:field='topMenu'>
|
||||||
|
<g:upFace><ui:msg>Hide</ui:msg></g:upFace>
|
||||||
|
<g:downFace><ui:msg>Show</ui:msg></g:downFace>
|
||||||
|
</g:ToggleButton></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Syntax Highlighting</ui:msg></th>
|
||||||
|
<td><g:ToggleButton ui:field='syntaxHighlighting'>
|
||||||
|
<g:upFace><ui:msg>Hide</ui:msg></g:upFace>
|
||||||
|
<g:downFace><ui:msg>Show</ui:msg></g:downFace>
|
||||||
|
</g:ToggleButton></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Show Tabs</ui:msg></th>
|
||||||
|
<td><g:ToggleButton ui:field='showTabs'>
|
||||||
|
<g:upFace><ui:msg>Hide</ui:msg></g:upFace>
|
||||||
|
<g:downFace><ui:msg>Show</ui:msg></g:downFace>
|
||||||
|
</g:ToggleButton></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Whitespace Errors</ui:msg></th>
|
||||||
|
<td><g:ToggleButton ui:field='whitespaceErrors'>
|
||||||
|
<g:upFace><ui:msg>Hide</ui:msg></g:upFace>
|
||||||
|
<g:downFace><ui:msg>Show</ui:msg></g:downFace>
|
||||||
|
</g:ToggleButton></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Line Numbers</ui:msg></th>
|
||||||
|
<td><g:ToggleButton ui:field='lineNumbers'>
|
||||||
|
<g:upFace><ui:msg>Hide</ui:msg></g:upFace>
|
||||||
|
<g:downFace><ui:msg>Show</ui:msg></g:downFace>
|
||||||
|
</g:ToggleButton></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<g:Button ui:field='apply' styleName='{style.apply}'>
|
||||||
|
<div><ui:msg>Apply</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
<g:Button ui:field='save' styleName='{style.save}'>
|
||||||
|
<div><ui:msg>Save</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
</ui:UiBinder>
|
@ -22,7 +22,8 @@ import com.google.gerrit.client.Dispatcher;
|
|||||||
import com.google.gerrit.client.Gerrit;
|
import com.google.gerrit.client.Gerrit;
|
||||||
import com.google.gerrit.client.JumpKeys;
|
import com.google.gerrit.client.JumpKeys;
|
||||||
import com.google.gerrit.client.VoidResult;
|
import com.google.gerrit.client.VoidResult;
|
||||||
import com.google.gerrit.client.account.DiffPreferences;
|
import com.google.gerrit.client.account.AccountApi;
|
||||||
|
import com.google.gerrit.client.account.EditPreferences;
|
||||||
import com.google.gerrit.client.changes.ChangeApi;
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
import com.google.gerrit.client.changes.ChangeEditApi;
|
import com.google.gerrit.client.changes.ChangeEditApi;
|
||||||
import com.google.gerrit.client.diff.DiffApi;
|
import com.google.gerrit.client.diff.DiffApi;
|
||||||
@ -42,6 +43,7 @@ import com.google.gerrit.client.rpc.ScreenLoadCallback;
|
|||||||
import com.google.gerrit.client.ui.InlineHyperlink;
|
import com.google.gerrit.client.ui.InlineHyperlink;
|
||||||
import com.google.gerrit.client.ui.Screen;
|
import com.google.gerrit.client.ui.Screen;
|
||||||
import com.google.gerrit.common.PageLinks;
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.extensions.client.EditPreferencesInfo;
|
||||||
import com.google.gerrit.reviewdb.client.Patch;
|
import com.google.gerrit.reviewdb.client.Patch;
|
||||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
import com.google.gwt.core.client.GWT;
|
import com.google.gwt.core.client.GWT;
|
||||||
@ -87,7 +89,8 @@ public class EditScreen extends Screen {
|
|||||||
private final PatchSet.Id revision;
|
private final PatchSet.Id revision;
|
||||||
private final String path;
|
private final String path;
|
||||||
private final int startLine;
|
private final int startLine;
|
||||||
private DiffPreferences prefs;
|
private EditPreferences prefs;
|
||||||
|
private EditPreferencesAction editPrefsAction;
|
||||||
private CodeMirror cm;
|
private CodeMirror cm;
|
||||||
private HttpResponse<NativeString> content;
|
private HttpResponse<NativeString> content;
|
||||||
private EditFileInfo editFileInfo;
|
private EditFileInfo editFileInfo;
|
||||||
@ -113,7 +116,6 @@ public class EditScreen extends Screen {
|
|||||||
this.revision = patch.getParentKey();
|
this.revision = patch.getParentKey();
|
||||||
this.path = patch.get();
|
this.path = patch.get();
|
||||||
this.startLine = startLine - 1;
|
this.startLine = startLine - 1;
|
||||||
prefs = DiffPreferences.create(Gerrit.getAccountDiffPreference());
|
|
||||||
add(uiBinder.createAndBindUi(this));
|
add(uiBinder.createAndBindUi(this));
|
||||||
addDomHandler(GlobalKey.STOP_PROPAGATION, KeyPressEvent.getType());
|
addDomHandler(GlobalKey.STOP_PROPAGATION, KeyPressEvent.getType());
|
||||||
}
|
}
|
||||||
@ -129,6 +131,26 @@ public class EditScreen extends Screen {
|
|||||||
protected void onLoad() {
|
protected void onLoad() {
|
||||||
super.onLoad();
|
super.onLoad();
|
||||||
|
|
||||||
|
EditPreferencesInfo current = Gerrit.getEditPreferences();
|
||||||
|
if (current == null) {
|
||||||
|
AccountApi.getEditPreferences(
|
||||||
|
new GerritCallback<EditPreferences>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(EditPreferences r) {
|
||||||
|
prefs = r;
|
||||||
|
EditPreferencesInfo global = new EditPreferencesInfo();
|
||||||
|
r.copyTo(global);
|
||||||
|
Gerrit.setEditPreferences(global);
|
||||||
|
onLoad2();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
prefs = EditPreferences.create(current);
|
||||||
|
onLoad2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onLoad2() {
|
||||||
CallbackGroup group1 = new CallbackGroup();
|
CallbackGroup group1 = new CallbackGroup();
|
||||||
final CallbackGroup group2 = new CallbackGroup();
|
final CallbackGroup group2 = new CallbackGroup();
|
||||||
final CallbackGroup group3 = new CallbackGroup();
|
final CallbackGroup group3 = new CallbackGroup();
|
||||||
@ -163,7 +185,6 @@ public class EditScreen extends Screen {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
if (revision.get() == 0) {
|
if (revision.get() == 0) {
|
||||||
ChangeEditApi.getMeta(revision, path,
|
ChangeEditApi.getMeta(revision, path,
|
||||||
group1.add(new AsyncCallback<EditFileInfo>() {
|
group1.add(new AsyncCallback<EditFileInfo>() {
|
||||||
@ -224,7 +245,6 @@ public class EditScreen extends Screen {
|
|||||||
@Override
|
@Override
|
||||||
protected void preDisplay(Void result) {
|
protected void preDisplay(Void result) {
|
||||||
initEditor(content);
|
initEditor(content);
|
||||||
content = null;
|
|
||||||
|
|
||||||
renderLinks(editFileInfo, diffLinks);
|
renderLinks(editFileInfo, diffLinks);
|
||||||
editFileInfo = null;
|
editFileInfo = null;
|
||||||
@ -300,9 +320,8 @@ public class EditScreen extends Screen {
|
|||||||
|
|
||||||
cm.adjustHeight(header.getOffsetHeight());
|
cm.adjustHeight(header.getOffsetHeight());
|
||||||
cm.on("cursorActivity", updateCursorPosition());
|
cm.on("cursorActivity", updateCursorPosition());
|
||||||
cm.extras().showTabs(prefs.showTabs());
|
setShowTabs(prefs.showTabs());
|
||||||
cm.extras().lineLength(
|
setLineLength(prefs.lineLength());
|
||||||
Patch.COMMIT_MSG.equals(path) ? 72 : prefs.lineLength());
|
|
||||||
cm.refresh();
|
cm.refresh();
|
||||||
cm.focus();
|
cm.focus();
|
||||||
|
|
||||||
@ -310,6 +329,7 @@ public class EditScreen extends Screen {
|
|||||||
cm.scrollToLine(startLine);
|
cm.scrollToLine(startLine);
|
||||||
}
|
}
|
||||||
updateActiveLine();
|
updateActiveLine();
|
||||||
|
editPrefsAction = new EditPreferencesAction(this, prefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -329,6 +349,15 @@ public class EditScreen extends Screen {
|
|||||||
JumpKeys.enable(true);
|
JumpKeys.enable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CodeMirror getEditor() {
|
||||||
|
return cm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("editSettings")
|
||||||
|
void onEditSetting(@SuppressWarnings("unused") ClickEvent e) {
|
||||||
|
editPrefsAction.show();
|
||||||
|
}
|
||||||
|
|
||||||
@UiHandler("save")
|
@UiHandler("save")
|
||||||
void onSave(@SuppressWarnings("unused") ClickEvent e) {
|
void onSave(@SuppressWarnings("unused") ClickEvent e) {
|
||||||
save().run();
|
save().run();
|
||||||
@ -342,6 +371,52 @@ public class EditScreen extends Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLineLength(int length) {
|
||||||
|
cm.extras().lineLength(
|
||||||
|
Patch.COMMIT_MSG.equals(path) ? 72 : length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setShowLineNumbers(boolean show) {
|
||||||
|
cm.setOption("lineNumbers", show);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setShowWhitespaceErrors(final boolean show) {
|
||||||
|
cm.operation(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
cm.setOption("showTrailingSpace", show);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void setShowTabs(boolean show) {
|
||||||
|
cm.extras().showTabs(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resizeCodeMirror() {
|
||||||
|
cm.adjustHeight(header.getOffsetHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSyntaxHighlighting(boolean b) {
|
||||||
|
ModeInfo modeInfo = ModeInfo.findMode(content.getContentType(), path);
|
||||||
|
final String mode = modeInfo != null ? modeInfo.mode() : null;
|
||||||
|
if (b && mode != null && !mode.isEmpty()) {
|
||||||
|
injectMode(mode, new AsyncCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Void result) {
|
||||||
|
cm.setOption("mode", mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
prefs.syntaxHighlighting(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cm.setOption("mode", (String) null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void upToChange() {
|
private void upToChange() {
|
||||||
Gerrit.display(PageLinks.toChangeInEditMode(revision.getParentKey()));
|
Gerrit.display(PageLinks.toChangeInEditMode(revision.getParentKey()));
|
||||||
}
|
}
|
||||||
@ -360,12 +435,12 @@ public class EditScreen extends Screen {
|
|||||||
.set("readOnly", false)
|
.set("readOnly", false)
|
||||||
.set("cursorBlinkRate", 0)
|
.set("cursorBlinkRate", 0)
|
||||||
.set("cursorHeight", 0.85)
|
.set("cursorHeight", 0.85)
|
||||||
.set("lineNumbers", true)
|
.set("lineNumbers", prefs.hideLineNumbers())
|
||||||
.set("tabSize", prefs.tabSize())
|
.set("tabSize", prefs.tabSize())
|
||||||
.set("lineWrapping", false)
|
.set("lineWrapping", false)
|
||||||
.set("scrollbarStyle", "overlay")
|
.set("scrollbarStyle", "overlay")
|
||||||
.set("styleSelectedText", true)
|
.set("styleSelectedText", true)
|
||||||
.set("showTrailingSpace", true)
|
.set("showTrailingSpace", prefs.showWhitespaceErrors())
|
||||||
.set("keyMap", "default")
|
.set("keyMap", "default")
|
||||||
.set("theme", prefs.theme().name().toLowerCase())
|
.set("theme", prefs.theme().name().toLowerCase())
|
||||||
.set("mode", mode != null ? mode.mode() : null));
|
.set("mode", mode != null ? mode.mode() : null));
|
||||||
|
@ -16,6 +16,7 @@ limitations under the License.
|
|||||||
-->
|
-->
|
||||||
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||||
|
<ui:with field='ico' type='com.google.gerrit.client.GerritResources'/>
|
||||||
<ui:style gss='false'>
|
<ui:style gss='false'>
|
||||||
@external .CodeMirror, .CodeMirror-cursor;
|
@external .CodeMirror, .CodeMirror-cursor;
|
||||||
|
|
||||||
@ -115,6 +116,13 @@ limitations under the License.
|
|||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
padding-right: 3px;
|
padding-right: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.preferences {
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
</ui:style>
|
</ui:style>
|
||||||
<g:HTMLPanel styleName='{style.header}'>
|
<g:HTMLPanel styleName='{style.header}'>
|
||||||
<div class='{style.headerLine}' ui:field='header'>
|
<div class='{style.headerLine}' ui:field='header'>
|
||||||
@ -135,6 +143,13 @@ limitations under the License.
|
|||||||
<span class='{style.path}'><span ui:field='project'/> / <span ui:field='filePath'/></span>
|
<span class='{style.path}'><span ui:field='project'/> / <span ui:field='filePath'/></span>
|
||||||
<div class='{style.navigation}'>
|
<div class='{style.navigation}'>
|
||||||
<g:FlowPanel ui:field='linkPanel' styleName='{style.linkPanel}'/>
|
<g:FlowPanel ui:field='linkPanel' styleName='{style.linkPanel}'/>
|
||||||
|
<g:Image
|
||||||
|
ui:field='editSettings'
|
||||||
|
styleName='{style.preferences}'
|
||||||
|
resource='{ico.gear}'
|
||||||
|
title='Edit screen preferences'>
|
||||||
|
<ui:attribute name='title'/>
|
||||||
|
</g:Image>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ui:field='editor' />
|
<div ui:field='editor' />
|
||||||
|
Loading…
Reference in New Issue
Block a user