mirror of
https://github.com/theonedev/onedev.git
synced 2025-12-08 18:26:30 +00:00
Store advanced search panel state and insert url panel state into session
This commit is contained in:
parent
9100c86b93
commit
e154e0e3f7
@ -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>
|
||||
@ -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();
|
||||
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
.project-file-picker {
|
||||
.blob-picker {
|
||||
padding: 8px 24px 8px 4px;
|
||||
max-width: 800px;
|
||||
min-width: 180px;
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -104,4 +104,5 @@ public interface BlobRenderContext extends Serializable {
|
||||
String getInitialNewPath();
|
||||
|
||||
String getAutosaveKey();
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user