/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.cyclop.web.panels.queryeditor.editor;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import javax.inject.Inject;
import org.apache.commons.lang.StringUtils;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;
import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.cyclop.model.ContextCqlCompletion;
import org.cyclop.model.CqlPart;
import org.cyclop.model.CqlQuery;
import org.cyclop.model.CqlQueryType;
import org.cyclop.service.completion.CompletionService;
import org.cyclop.web.common.JsFunctionBuilder;
/** @author Maciej Miklas */
public class EditorPanel extends Panel {
private static final JavaScriptResourceReference SUGGEST = new JavaScriptResourceReference(EditorPanel.class,
"asuggest.js");
private String editorMarkupIdJq;
private String editorMarkupIdJs;
@Inject
private CompletionService completionService;
private ContextCqlCompletion currentCompletion;
private ContextCqlCompletion lastCompletion;
private final List<CompletionChangeListener> completionChangeListeners = new ArrayList<>();
private TextArea<String> editor;
private final IModel<String> editorModel = new Model<>();
public EditorPanel(String id, String editorContent) {
super(id);
if (editorContent != null) {
editorModel.setObject(editorContent);
}
}
@Override
protected void onInitialize() {
super.onInitialize();
initEditor();
editorMarkupIdJq = "#" + editor.getMarkupId();
editorMarkupIdJs = editor.getMarkupId();
}
public void registerCompletionChangeListener(CompletionChangeListener list) {
completionChangeListeners.add(list);
}
public void resetCompletion() {
if (currentCompletion != null) {
lastCompletion = currentCompletion;
}
currentCompletion = null;
}
public CqlQuery getEditorContent() {
String editorValue = editor.getDefaultModelObjectAsString();
editorValue = StringUtils.trimToNull(editorValue);
ContextCqlCompletion completion = currentCompletion == null ? lastCompletion : currentCompletion;
if (editorValue == null || completion == null) {
return null;
}
CqlQuery cq = new CqlQuery(completion.queryName, editorValue);
return cq;
}
private void initEditor() {
editor = new TextArea<>("queryEditor", editorModel);
editor.setEscapeModelStrings(false);
add(editor);
editor.add(new OnChangeAjaxBehavior() {
@Override
protected void onUpdate(AjaxRequestTarget target) {
Component cmp = getComponent();
String editorValue = cmp.getDefaultModelObjectAsString();
ContextCqlCompletion cqlCompletion;
if (StringUtils.isEmpty(editorValue)) {
cqlCompletion = completionService.findInitialCompletion();
} else {
RequestCycle requestCycle = RequestCycle.get();
int index = requestCycle.getRequest().getRequestParameters().getParameterValue("cursorPos").toInt();
CqlQuery cqlQuery = new CqlQuery(CqlQueryType.UNKNOWN, editorValue);
cqlCompletion = completionService.findCompletion(cqlQuery, index);
}
if (cqlCompletion.cqlCompletion.isEmpty() || cqlCompletion.equals(currentCompletion)) {
return;
}
fireCompletionChanged(cqlCompletion);
String suggestsScript = generateReplaceSuggestsJs(editorMarkupIdJq,
cqlCompletion.cqlCompletion.fullCompletion);
target.appendJavaScript(suggestsScript);
for (CompletionChangeListener list : completionChangeListeners) {
Component refresh = list.getReferencesForRefresh();
if (refresh == null) {
continue;
}
target.add(refresh);
}
}
@Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
attributes.getDynamicExtraParameters().add(
"return {'cursorPos' : getCaretPosition(" + editorMarkupIdJs + ")}");
super.updateAjaxAttributes(attributes);
}
});
}
private void fireCompletionChanged(ContextCqlCompletion currentCompletion) {
this.currentCompletion = currentCompletion;
for (CompletionChangeListener list : completionChangeListeners) {
list.onCompletionChange(currentCompletion);
}
}
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(JavaScriptReferenceHeaderItem.forReference(SUGGEST));
ContextCqlCompletion cqlCompletion = completionService.findInitialCompletion();
fireCompletionChanged(cqlCompletion);
String suggestsScript = generateInitSuggestsJs(editorMarkupIdJq, cqlCompletion.cqlCompletion.fullCompletion);
response.render(OnDomReadyHeaderItem.forScript(suggestsScript));
}
private String generateInitSuggestsJs(String editorMarkupId, SortedSet<? extends CqlPart> suggestValues) {
return generateSuggests("initSuggests", editorMarkupId, suggestValues);
}
private String generateReplaceSuggestsJs(String editorMarkupId, SortedSet<? extends CqlPart> suggestValues) {
return generateSuggests("replaceSuggests", editorMarkupId, suggestValues);
}
private String generateSuggests(String function, String editorMarkupId, SortedSet<? extends CqlPart> suggestValues) {
String js = JsFunctionBuilder.function(function).param(editorMarkupId).array(suggestValues).build();
return js;
}
}