Store advanced search panel state and insert url panel state into session

This commit is contained in:
Robin Shen 2018-03-05 21:57:03 +08:00
parent 9100c86b93
commit e154e0e3f7
18 changed files with 211 additions and 153 deletions

View File

@ -1,5 +1,5 @@
<wicket:panel>
<div wicket:id="tree" class="project-file-picker"></div>
<div wicket:id="tree" class="blob-picker"></div>
<wicket:fragment wicket:id="folderFrag">
<span wicket:id="icon"></span> <span wicket:id="label"></span>
</wicket:fragment>

View File

@ -1,4 +1,4 @@
package com.turbodev.server.web.component.projectfilepicker;
package com.turbodev.server.web.component.blobpicker;
import java.util.Iterator;
import java.util.List;
@ -28,11 +28,11 @@ import com.turbodev.server.web.component.BlobIcon;
import com.turbodev.server.web.component.link.ViewStateAwareAjaxLink;
@SuppressWarnings("serial")
public abstract class ProjectFilePicker extends Panel {
public abstract class BlobPicker extends Panel {
private final ObjectId commitId;
public ProjectFilePicker(String id, ObjectId commitId) {
public BlobPicker(String id, ObjectId commitId) {
super(id);
this.commitId = commitId;
@ -83,6 +83,12 @@ public abstract class ProjectFilePicker extends Panel {
add(new HumanTheme());
}
@Override
public void collapse(BlobIdent blobIdent) {
super.collapse(blobIdent);
onStateChange();
}
@Override
public void expand(BlobIdent blobIdent) {
super.expand(blobIdent);
@ -90,18 +96,20 @@ public abstract class ProjectFilePicker extends Panel {
List<BlobIdent> children = getProject().getChildren(blobIdent, getBlobIdentFilter(), commitId);
if (children.size() == 1 && children.get(0).isTree())
expand(children.get(0));
onStateChange();
}
@Override
protected Component newContentComponent(String id, IModel<BlobIdent> node) {
BlobIdent blobIdent = node.getObject();
if (blobIdent.isTree()) {
Fragment fragment = new Fragment(id, "folderFrag", ProjectFilePicker.this);
Fragment fragment = new Fragment(id, "folderFrag", BlobPicker.this);
fragment.add(new BlobIcon("icon", node));
fragment.add(new Label("label", blobIdent.getName()));
return fragment;
} else {
Fragment fragment = new Fragment(id, "fileFrag", ProjectFilePicker.this);
Fragment fragment = new Fragment(id, "fileFrag", BlobPicker.this);
AjaxLink<Void> link = new ViewStateAwareAjaxLink<Void>("link") {
@Override
@ -124,7 +132,11 @@ public abstract class ProjectFilePicker extends Panel {
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(CssHeaderItem.forReference(new ProjectFilePickerResourceReference()));
response.render(CssHeaderItem.forReference(new BlobPickerResourceReference()));
}
protected void onStateChange() {
}
protected abstract Project getProject();

View File

@ -0,0 +1,12 @@
package com.turbodev.server.web.component.blobpicker;
import com.turbodev.server.web.page.base.BaseDependentCssResourceReference;
@SuppressWarnings("serial")
public class BlobPickerResourceReference extends BaseDependentCssResourceReference {
public BlobPickerResourceReference() {
super(BlobPickerResourceReference.class, "blob-picker.css");
}
}

View File

@ -1,4 +1,4 @@
.project-file-picker {
.blob-picker {
padding: 8px 24px 8px 4px;
max-width: 800px;
min-width: 180px;

View File

@ -5,6 +5,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -14,6 +15,7 @@ import javax.activation.MimetypesFileTypeMap;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.wicket.Component;
import org.apache.wicket.MetaDataKey;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
@ -33,6 +35,7 @@ import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.protocol.http.WebSession;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.util.lang.Bytes;
import org.eclipse.jgit.lib.FileMode;
@ -42,8 +45,8 @@ import com.google.common.base.Preconditions;
import com.turbodev.server.git.BlobIdent;
import com.turbodev.server.git.BlobIdentFilter;
import com.turbodev.server.model.Project;
import com.turbodev.server.web.component.blobpicker.BlobPicker;
import com.turbodev.server.web.component.dropzonefield.DropzoneField;
import com.turbodev.server.web.component.projectfilepicker.ProjectFilePicker;
import com.turbodev.server.web.component.tabbable.AjaxActionTab;
import com.turbodev.server.web.component.tabbable.Tab;
import com.turbodev.server.web.component.tabbable.Tabbable;
@ -59,6 +62,12 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel
abstract class InsertUrlPanel extends Panel {
private static final MimetypesFileTypeMap MIME_TYPES = new MimetypesFileTypeMap();
private static final MetaDataKey<String> ACTIVE_TAB = new MetaDataKey<String>(){};
private static final MetaDataKey<String> UPLOAD_DIRECTORY = new MetaDataKey<String>(){};
private static final MetaDataKey<HashSet<String>> BLOB_PICKER_STATE = new MetaDataKey<HashSet<String>>(){};
static final String TAB_INPUT_URL = "Input URL";
@ -171,7 +180,13 @@ abstract class InsertUrlPanel extends Panel {
throw new RuntimeException(e);
}
Set<BlobIdent> filePickerState = markdownEditor.getFilePickerState();
Set<BlobIdent> blobPickerState = new HashSet<>();
Set<String> expandedPaths = WebSession.get().getMetaData(BLOB_PICKER_STATE);
if (expandedPaths != null) {
for (String path: expandedPaths)
blobPickerState.add(new BlobIdent(commitId.name(), path, FileMode.TREE.getBits()));
}
BlobIdent blobIdent = context.getBlobIdent();
String parentPath;
if (blobIdent.isTree())
@ -182,14 +197,14 @@ abstract class InsertUrlPanel extends Panel {
parentPath = null;
while (parentPath != null) {
filePickerState.add(new BlobIdent(commitId.name(), parentPath, FileMode.TYPE_TREE));
blobPickerState.add(new BlobIdent(commitId.name(), parentPath, FileMode.TYPE_TREE));
if (parentPath.contains("/"))
parentPath = StringUtils.substringBeforeLast(parentPath, "/");
else
parentPath = null;
}
fragment.add(new ProjectFilePicker("files", commitId) {
fragment.add(new BlobPicker("files", commitId) {
@Override
protected void onSelect(AjaxRequestTarget target, BlobIdent blobIdent) {
@ -212,9 +227,17 @@ abstract class InsertUrlPanel extends Panel {
return markdownEditor.getBlobRenderContext().getProject();
}
@Override
protected void onStateChange() {
HashSet<String> expandedPaths = new HashSet<>();
for (BlobIdent blobIdent: blobPickerState)
expandedPaths.add(blobIdent.path);
WebSession.get().setMetaData(BLOB_PICKER_STATE, expandedPaths);
}
@Override
protected Set<BlobIdent> getState() {
return markdownEditor.getFilePickerState();
return blobPickerState;
}
});
@ -378,12 +401,27 @@ abstract class InsertUrlPanel extends Panel {
form.add(new DropzoneField("file", model, acceptedFiles, 1, Project.MAX_UPLOAD_SIZE).setRequired(true));
form.add(new TextField<String>("directory",
new PropertyModel<String>(markdownEditor, "uploadDirectory")));
form.add(new TextField<String>("directory", new IModel<String>() {
@Override
public void detach() {
}
@Override
public String getObject() {
return WebSession.get().getMetaData(UPLOAD_DIRECTORY);
}
@Override
public void setObject(String object) {
WebSession.get().setMetaData(UPLOAD_DIRECTORY, object);
}
}));
form.add(new TextField<String>("summaryCommitMessage",
new PropertyModel<String>(InsertUrlPanel.this, "summaryCommitMessage")));
new PropertyModel<String>(this, "summaryCommitMessage")));
form.add(new TextArea<String>("detailCommitMessage",
new PropertyModel<String>(InsertUrlPanel.this, "detailCommitMessage")));
new PropertyModel<String>(this, "detailCommitMessage")));
form.add(new AjaxButton("insert") {
@ -400,7 +438,7 @@ abstract class InsertUrlPanel extends Panel {
commitMessage += "\n\n" + detailCommitMessage;
try {
String directory = markdownEditor.getUploadDirectory();
String directory = WebSession.get().getMetaData(UPLOAD_DIRECTORY);
context.uploadFiles(uploads, directory, commitMessage);
String fileName = uploads.iterator().next().getClientFileName();
String url;
@ -450,7 +488,7 @@ abstract class InsertUrlPanel extends Panel {
Component content = newInputUrlPanel();
target.add(content);
fragment.replace(content);
markdownEditor.setActiveInsertUrlTab(TAB_INPUT_URL);
WebSession.get().setMetaData(ACTIVE_TAB, TAB_INPUT_URL);
}
};
@ -463,7 +501,7 @@ abstract class InsertUrlPanel extends Panel {
Component content = newPickExistingPanel();
target.add(content);
fragment.replace(content);
markdownEditor.setActiveInsertUrlTab(TAB_PICK_EXISTING);
WebSession.get().setMetaData(ACTIVE_TAB, TAB_PICK_EXISTING);
}
};
@ -476,7 +514,7 @@ abstract class InsertUrlPanel extends Panel {
Component content = newUploadPanel();
target.add(content);
fragment.replace(content);
markdownEditor.setActiveInsertUrlTab(TAB_UPLOAD);
WebSession.get().setMetaData(ACTIVE_TAB, TAB_UPLOAD);
}
};
@ -485,15 +523,16 @@ abstract class InsertUrlPanel extends Panel {
fragment.add(new Tabbable("tabs", tabs));
inputUrlTab.setSelected(false);
if (markdownEditor.getActiveInsertUrlTab().equals(TAB_INPUT_URL)) {
inputUrlTab.setSelected(true);
fragment.add(newInputUrlPanel());
} else if (markdownEditor.getActiveInsertUrlTab().equals(TAB_PICK_EXISTING)) {
String activeTab = WebSession.get().getMetaData(ACTIVE_TAB);
if (TAB_PICK_EXISTING.equals(activeTab)) {
pickExistingTab.setSelected(true);
fragment.add(newPickExistingPanel());
} else {
} else if (TAB_UPLOAD.equals(activeTab)) {
uploadTab.setSelected(true);
fragment.add(newUploadPanel());
} else {
inputUrlTab.setSelected(true);
fragment.add(newInputUrlPanel());
}
add(fragment);
}

View File

@ -6,10 +6,8 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import javax.servlet.http.Cookie;
@ -44,11 +42,10 @@ import org.unbescape.javascript.JavaScriptEscape;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.turbodev.launcher.loader.AppLoader;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.turbodev.launcher.loader.AppLoader;
import com.turbodev.server.TurboDev;
import com.turbodev.server.git.BlobIdent;
import com.turbodev.server.manager.MarkdownManager;
import com.turbodev.server.model.PullRequest;
import com.turbodev.server.util.facade.UserFacade;
@ -75,12 +72,6 @@ public class MarkdownEditor extends FormComponentPanel<String> {
private AbstractPostAjaxBehavior ajaxBehavior;
private String activeInsertUrlTab = InsertUrlPanel.TAB_INPUT_URL;
private String uploadDirectory;
private Set<BlobIdent> filePickerState = new HashSet<>();
/**
* @param id
* component id of the editor
@ -451,28 +442,4 @@ public class MarkdownEditor extends FormComponentPanel<String> {
return blobRenderContext;
}
public String getActiveInsertUrlTab() {
return activeInsertUrlTab;
}
public void setActiveInsertUrlTab(String activeInsertUrlTab) {
this.activeInsertUrlTab = activeInsertUrlTab;
}
public String getUploadDirectory() {
return uploadDirectory;
}
public void setUploadDirectory(String uploadDirectory) {
this.uploadDirectory = uploadDirectory;
}
public Set<BlobIdent> getFilePickerState() {
return filePickerState;
}
public void setFilePickerState(Set<BlobIdent> filePickerState) {
this.filePickerState = filePickerState;
}
}

View File

@ -1,12 +0,0 @@
package com.turbodev.server.web.component.projectfilepicker;
import com.turbodev.server.web.page.base.BaseDependentCssResourceReference;
@SuppressWarnings("serial")
public class ProjectFilePickerResourceReference extends BaseDependentCssResourceReference {
public ProjectFilePickerResourceReference() {
super(ProjectFilePickerResourceReference.class, "project-file-picker.css");
}
}

View File

@ -535,7 +535,7 @@ turbodev.server = {
util: {
canInput: function(element) {
var $element = $(element);
return ($element.is("input") || $element.is("textarea") && $element.is("select")) && !$element.hasClass("readonly");
return ($element.is("input") || $element.is("textarea") || $element.is("select")) && !$element.hasClass("readonly");
},
isDevice: function() {
var ua = navigator.userAgent.toLowerCase();

View File

@ -581,34 +581,45 @@ public class ProjectBlobPage extends ProjectPage implements BlobRenderContext {
};
}
private AdvancedSearchPanel advancedSearchPanel;
private ModalPanel advancedSearchPanelModal;
private AdvancedSearchPanel newAdvancedSearchPanel(String id, ModalPanel modal) {
return new AdvancedSearchPanel(id, projectModel, new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
return state.blobIdent.revision;
}
}) {
@Override
protected void onSearchComplete(AjaxRequestTarget target, List<QueryHit> hits) {
newSearchResult(target, hits);
resizeWindow(target);
modal.close();
}
@Override
protected void onCancel(AjaxRequestTarget target) {
modal.close();
}
@Override
protected BlobIdent getCurrentBlob() {
return state.blobIdent;
}
};
/*
* Re-use advanced search panel instance so that search options can be preserved in the page
*/
advancedSearchPanelModal = modal;
if (advancedSearchPanel == null) {
advancedSearchPanel = new AdvancedSearchPanel(id, projectModel, new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
return state.blobIdent.revision;
}
}) {
@Override
protected void onSearchComplete(AjaxRequestTarget target, List<QueryHit> hits) {
newSearchResult(target, hits);
resizeWindow(target);
advancedSearchPanelModal.close();
}
@Override
protected void onCancel(AjaxRequestTarget target) {
advancedSearchPanelModal.close();
}
@Override
protected BlobIdent getCurrentBlob() {
return state.blobIdent;
}
};
}
return advancedSearchPanel;
}
private void newBlobContent(@Nullable AjaxRequestTarget target) {
@ -847,6 +858,7 @@ public class ProjectBlobPage extends ProjectPage implements BlobRenderContext {
@Override
public void onSelect(AjaxRequestTarget target, BlobIdent blobIdent, @Nullable TokenPosition tokenPos) {
TextRange prevMark = state.mark;
state.mark = TextRange.of(tokenPos);
if (!blobIdent.revision.equals(state.blobIdent.revision)) {
state.blobIdent = blobIdent;
@ -857,7 +869,7 @@ public class ProjectBlobPage extends ProjectPage implements BlobRenderContext {
onResolvedRevisionChange(target);
} else {
if (!Objects.equal(state.blobIdent.path, blobIdent.path)
|| state.mark != null && !(get(BLOB_CONTENT_ID) instanceof Markable)) {
|| (state.mark != null) != (prevMark != null)) {
state.blobIdent.path = blobIdent.path;
state.blobIdent.mode = blobIdent.mode;
state.mode = Mode.VIEW;

View File

@ -89,8 +89,8 @@ turbodev.server.projectBlob = {
});
/*
* Do not use hotkey plugin here as otherwise codemirror readonly mode can not focus
* to search
* Do not use hotkey plugin here as otherwise codemirror search will not function
* properly in readonly mode
*/
$(document).on("keydown", function(e) {
if ($(".modal:visible").length == 0 && !turbodev.server.util.canInput(e.target)) {

View File

@ -104,4 +104,5 @@ public interface BlobRenderContext extends Serializable {
String getInitialNewPath();
String getAutosaveKey();
}

View File

@ -83,7 +83,8 @@ turbodev.server.sourceEdit = {
var autosaveValue = localStorage.getItem(autosaveKey);
if (autosaveValue) {
cm.doc.setValue(autosaveValue);
$warning.show();
$warning.show();
$(window).resize();
}
if (mark && turbodev.server.viewState.getFromHistory() === undefined

View File

@ -57,8 +57,8 @@ turbodev.server.sourceView = {
$(document).data("SourceViewShortcutsBinded", true);
/*
* Do not use hotkey plugin here as otherwise codemirror readonly mode can not focus
* to search
* Do not use hotkey plugin here as otherwise codemirror search will not function
* properly in readonly mode
*/
$(document).on("keydown", function(e) {
if ($(".modal:visible").length == 0 && !turbodev.server.util.canInput(e.target)

View File

@ -2,16 +2,16 @@ package com.turbodev.server.web.page.project.blob.search.advanced;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.annotation.Nullable;
import javax.servlet.http.Cookie;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.shiro.codec.Base64;
import org.apache.wicket.Component;
import org.apache.wicket.MetaDataKey;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
@ -28,18 +28,12 @@ import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.http.WebRequest;
import org.apache.wicket.request.http.WebResponse;
import org.apache.wicket.validation.IErrorMessageSource;
import org.apache.wicket.validation.INullAcceptingValidator;
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.IValidationError;
import org.eclipse.jgit.lib.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.turbodev.utils.StringUtils;
import com.turbodev.server.TurboDev;
import com.turbodev.server.git.BlobIdent;
import com.turbodev.server.model.Project;
@ -50,20 +44,25 @@ import com.turbodev.server.search.query.FileQuery;
import com.turbodev.server.search.query.SymbolQuery;
import com.turbodev.server.search.query.TextQuery;
import com.turbodev.server.search.query.TooGeneralQueryException;
import com.turbodev.server.web.WebSession;
import com.turbodev.server.web.behavior.RunTaskBehavior;
import com.turbodev.server.web.component.tabbable.AjaxActionTab;
import com.turbodev.server.web.component.tabbable.Tab;
import com.turbodev.server.web.component.tabbable.Tabbable;
import com.turbodev.server.web.page.project.blob.search.result.SearchResultPanel;
import com.turbodev.utils.StringUtils;
import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
import jersey.repackaged.com.google.common.base.Throwables;
@SuppressWarnings("serial")
public abstract class AdvancedSearchPanel extends Panel {
private static final String COOKIE_SEARCH_TYPE = "blob.search.advanced.type";
private static final MetaDataKey<Class<? extends SearchOption>> ACTIVE_TAB =
new MetaDataKey<Class<? extends SearchOption>>(){};
private static final Logger logger = LoggerFactory.getLogger(AdvancedSearchPanel.class);
private static final MetaDataKey<HashMap<Class<?>, SearchOption>> SEARCH_OPTIONS =
new MetaDataKey<HashMap<Class<?>, SearchOption>>(){};
private final IModel<Project> projectModel;
@ -79,13 +78,12 @@ public abstract class AdvancedSearchPanel extends Panel {
this.projectModel = projectModel;
this.revisionModel = revisionModel;
WebRequest request = (WebRequest) RequestCycle.get().getRequest();
Cookie cookie = request.getCookie(COOKIE_SEARCH_TYPE);
if (cookie != null) {
Class<? extends SearchOption> activeTab = WebSession.get().getMetaData(ACTIVE_TAB);
if (activeTab != null) {
try {
option = (SearchOption) Class.forName(cookie.getValue()).newInstance();
option = activeTab.newInstance();
} catch (Exception e) {
logger.debug("Error restoring search option from cookie", e);
Throwables.propagate(e);
}
}
}
@ -160,11 +158,10 @@ public abstract class AdvancedSearchPanel extends Panel {
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
WebResponse response = (WebResponse) RequestCycle.get().getResponse();
byte[] bytes = SerializationUtils.serialize(option);
Cookie cookie = new Cookie(option.getClass().getName(), Base64.encodeToString(bytes));
cookie.setMaxAge(Integer.MAX_VALUE);
response.addCookie(cookie);
HashMap<Class<?>, SearchOption> savedOptions = getSavedOptions();
savedOptions.put(option.getClass(), option);
WebSession.get().setMetaData(SEARCH_OPTIONS, savedOptions);
onSearchComplete(target, hits);
}
@ -198,10 +195,7 @@ public abstract class AdvancedSearchPanel extends Panel {
}
private void onSelectTab(AjaxRequestTarget target) {
WebResponse response = (WebResponse) RequestCycle.get().getResponse();
Cookie cookie = new Cookie(COOKIE_SEARCH_TYPE, option.getClass().getName());
cookie.setMaxAge(Integer.MAX_VALUE);
response.addCookie(cookie);
WebSession.get().setMetaData(ACTIVE_TAB, option.getClass());
SearchOptionEditor editor = newSearchOptionEditor(option);
form.replace(editor);
target.add(editor);
@ -216,6 +210,13 @@ public abstract class AdvancedSearchPanel extends Panel {
return newTextSearchOptionEditor();
}
private HashMap<Class<?>, SearchOption> getSavedOptions() {
HashMap<Class<?>, SearchOption> savedOptions = WebSession.get().getMetaData(SEARCH_OPTIONS);
if (savedOptions == null)
savedOptions = new HashMap<>();
return savedOptions;
}
private SearchOptionEditor newSymbolSearchOptionEditor() {
return new SearchOptionEditor("symbolSearchFrag") {
@ -496,17 +497,10 @@ public abstract class AdvancedSearchPanel extends Panel {
public SearchOptionEditor(String markupId) {
super("searchOptions", markupId, AdvancedSearchPanel.this);
WebRequest request = (WebRequest) RequestCycle.get().getRequest();
Cookie cookie = request.getCookie(option.getClass().getName());
if (cookie != null) {
try {
byte[] bytes = Base64.decode(cookie.getValue());
option = (SearchOption) SerializationUtils.deserialize(bytes);
} catch (Exception e) {
logger.debug("Error restoring search option from cookie", e);
}
}
Map<Class<?>, SearchOption> savedOptions = getSavedOptions();
if (savedOptions.containsKey(option.getClass()))
option = savedOptions.get(option.getClass());
}
@Override

View File

@ -8,12 +8,16 @@ class ConfirmSwitchFileListener implements IAjaxCallListener {
private final String path;
private final boolean hasMark;
public ConfirmSwitchFileListener() {
path = null;
hasMark = false;
}
public ConfirmSwitchFileListener(String path) {
public ConfirmSwitchFileListener(String path, boolean hasMark) {
this.path = path;
this.hasMark = hasMark;
}
@Override
@ -24,8 +28,8 @@ class ConfirmSwitchFileListener implements IAjaxCallListener {
@Override
public CharSequence getPrecondition(Component component) {
if (path != null) {
return String.format("return turbodev.server.searchResult.confirmSwitchFileByPath('%s');",
StringEscapeUtils.escapeEcmaScript(path));
return String.format("return turbodev.server.searchResult.confirmSwitchFileByPath('%s', %b);",
StringEscapeUtils.escapeEcmaScript(path), hasMark);
} else {
return String.format("return turbodev.server.searchResult.confirmSwitchFileByLink('%s');",
component.getMarkupId(true));

View File

@ -28,6 +28,7 @@ import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.eclipse.jgit.lib.FileMode;
import com.turbodev.jsymbol.TokenPosition;
import com.turbodev.jsymbol.util.HighlightableLabel;
import com.turbodev.server.git.BlobIdent;
import com.turbodev.server.model.support.TextRange;
@ -161,6 +162,14 @@ public abstract class SearchResultPanel extends Panel {
return activeBlob.getBlobPath();
}
private TokenPosition getActiveBlobMark(ActiveIndex activeIndex) {
MatchedBlob activeBlob = blobs.get(activeIndex.blob);
if (activeIndex.hit != -1)
return activeBlob.getHits().get(activeIndex.hit).getTokenPos();
else
return null;
}
private ActiveIndex getPrevMatch() {
if (prevMatchLink.isEnabled()) {
ActiveIndex activeIndex = new ActiveIndex(activeBlobIndex, activeHitIndex);
@ -229,6 +238,13 @@ public abstract class SearchResultPanel extends Panel {
}
}
private String getUrlPath(String blobPath) {
ProjectBlobPage.State state = new ProjectBlobPage.State();
state.blobIdent = new BlobIdent(context.getBlobIdent());
state.blobIdent.path = blobPath;
return RequestCycle.get().urlFor(ProjectBlobPage.class, ProjectBlobPage.paramsOf(context.getProject(), state)).toString();
}
@Override
protected void onInitialize() {
super.onInitialize();
@ -242,8 +258,13 @@ public abstract class SearchResultPanel extends Panel {
protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
super.updateAjaxAttributes(attributes);
ActiveIndex activeIndex = getPrevMatch();
if (activeIndex != null)
attributes.getAjaxCallListeners().add(new ConfirmSwitchFileListener(getActiveBlobPath(activeIndex)));
if (activeIndex != null) {
String prevBlobPath = getActiveBlobPath(activeIndex);
TokenPosition prevTokenPos = getActiveBlobMark(activeIndex);
String prevUrlPath = getUrlPath(prevBlobPath);
attributes.getAjaxCallListeners().add(new ConfirmSwitchFileListener(prevUrlPath, prevTokenPos!=null));
}
}
@Override
@ -267,9 +288,14 @@ public abstract class SearchResultPanel extends Panel {
@Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
super.updateAjaxAttributes(attributes);
ActiveIndex activeIndex = getNextMatch();
if (activeIndex != null)
attributes.getAjaxCallListeners().add(new ConfirmSwitchFileListener(getActiveBlobPath(activeIndex)));
ActiveIndex nextIndex = getNextMatch();
if (nextIndex != null) {
String nextBlobPath = getActiveBlobPath(nextIndex);
TokenPosition nextTokenPos = getActiveBlobMark(nextIndex);
String nextUrlPath = getUrlPath(nextBlobPath);
attributes.getAjaxCallListeners().add(new ConfirmSwitchFileListener(nextUrlPath, nextTokenPos!=null));
}
}
@Override

View File

@ -7,6 +7,7 @@ import org.apache.wicket.markup.head.HeaderItem;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.request.resource.CssResourceReference;
import com.turbodev.server.web.asset.scrollintoview.ScrollIntoViewResourceReference;
import com.turbodev.server.web.asset.uri.URIResourceReference;
import com.turbodev.server.web.page.base.BaseDependentResourceReference;
@ -22,6 +23,7 @@ public class SearchResultResourceReference extends BaseDependentResourceReferenc
public List<HeaderItem> getDependencies() {
List<HeaderItem> dependencies = super.getDependencies();
dependencies.add(JavaScriptHeaderItem.forReference(new URIResourceReference()));
dependencies.add(JavaScriptHeaderItem.forReference(new ScrollIntoViewResourceReference()));
dependencies.add(CssHeaderItem.forReference(
new CssResourceReference(SearchResultResourceReference.class, "search-result.css")));
return dependencies;

View File

@ -2,14 +2,14 @@ turbodev.server.searchResult = {
confirmSwitchFileByLink: function(linkId) {
var linkURI = new URI(document.getElementById(linkId));
var currentURI = new URI(window.location.href);
if (linkURI.path() != currentURI.path())
if (linkURI.path() != currentURI.path() || linkURI.hasQuery("mark") != currentURI.hasQuery("mark"))
return turbodev.server.form.confirmLeave();
else
return true;
},
confirmSwitchFileByPath: function(path) {
confirmSwitchFileByPath: function(path, hasMark) {
var currentURI = new URI(window.location.href);
if (path != currentURI.path())
if (path != currentURI.path() || hasMark != currentURI.hasQuery("mark"))
return turbodev.server.form.confirmLeave();
else
return true;