/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.web.wicket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.ajax.IAjaxCallDecorator;
import org.apache.wicket.ajax.calldecorator.AjaxCallDecorator;
import org.apache.wicket.behavior.AbstractBehavior;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.FormComponentPanel;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
/**
* A XML editor based on CodeMirror
* @author Andrea Aime
*/
@SuppressWarnings("serial")
public class CodeMirrorEditor extends FormComponentPanel<String> {
public static final ResourceReference REFERENCE = new ResourceReference(
CodeMirrorEditor.class, "js/codemirror/js/codemirror.js");
private TextArea<String> editor;
private WebMarkupContainer container;
public CodeMirrorEditor(String id, IModel<String> model) {
super(id, model);
container = new WebMarkupContainer("editorContainer");
container.setOutputMarkupId(true);
add(container);
editor = new TextArea<String>("editor", new Model<String>((String) model.getObject()));
container.add(editor);
editor.setOutputMarkupId(true);
editor.add(new CodeMirrorBehavior());
}
@Override
protected void onBeforeRender() {
editor.setModelObject(getModelObject());
super.onBeforeRender();
}
@Override
protected void convertInput() {
editor.processInput();
setConvertedInput(editor.getConvertedInput());
}
@Override
public String getInput() {
return editor.getInput();
}
public void setTextAreaMarkupId(String id) {
editor.setMarkupId(id);
}
public String getTextAreaMarkupId() {
return editor.getMarkupId();
}
public void reset() {
super.validate();
editor.validate();
editor.clearInput();
}
public IAjaxCallDecorator getSaveDecorator() {
// we need to force CodeMirror to update the textarea contents (which it hid)
// before submitting the form, otherwise the validation will use the old contents
return new AjaxCallDecorator() {
@Override
public CharSequence decorateScript(CharSequence script) {
// textarea.value = codemirrorinstance.getCode()
String id = getTextAreaMarkupId();
return "document.getElementById('" + id + "').value = document.gsEditors." + id + ".getCode();" + script;
}
};
}
class CodeMirrorBehavior extends AbstractBehavior {
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.renderJavascriptReference(REFERENCE);
response.renderOnDomReadyJavascript(getInitJavascript());
}
private String getInitJavascript() {
InputStream is = CodeMirrorEditor.class.getResourceAsStream("CodeMirrorEditor.js");
String js = convertStreamToString(is);
js = js.replaceAll("\\$componentId", editor.getMarkupId());
js = js.replaceAll("\\$syntax", "parsexml.js");
js = js.replaceAll("\\$container", container.getMarkupId());
js = js.replaceAll("\\$stylesheet", "./resources/org.geoserver.web.wicket.CodeMirrorEditor/js/codemirror/css/xmlcolors.css");
return js;
}
public String convertStreamToString(InputStream is) {
/*
* To convert the InputStream to String we use the Reader.read(char[] buffer) method. We
* iterate until the Reader return -1 which means there's no more data to read. We use
* the StringWriter class to produce the string.
*/
try {
if (is != null) {
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} finally {
is.close();
}
return writer.toString();
} else {
return "";
}
} catch (IOException e) {
throw new RuntimeException("Did not expect this one...", e);
}
}
}
}