1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.gui.dialog;
35
36 import info.magnolia.cms.core.NodeData;
37 import info.magnolia.cms.gui.control.Edit;
38 import info.magnolia.cms.gui.misc.CssConstants;
39 import info.magnolia.cms.util.BooleanUtil;
40
41 import java.io.IOException;
42 import java.io.Writer;
43 import java.util.HashMap;
44 import java.util.Map;
45
46 import javax.jcr.PropertyType;
47
48 import org.apache.commons.lang.StringUtils;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 public class DialogEditCode extends DialogBox {
75
76
77
78
79 private static final String ATTRIBUTE_CODEMIRROR_LOADED = "info.magnolia.cms.gui.dialog.codemirror.loaded";
80
81 private static final Logger log = LoggerFactory.getLogger(DialogEditCode.class);
82
83
84
85 public static final Map<String,String> availableParsers = new HashMap<String,String>();
86
87
88
89
90 public static final Long LINE_HEIGHT = 16L;
91
92 static {
93 availableParsers.put("js", "JSParser");
94 availableParsers.put("javascript", "JSParser");
95 availableParsers.put("processedJs", "JSParser");
96 availableParsers.put("css", "CSSParser");
97 availableParsers.put("processedCss", "CSSParser");
98 availableParsers.put("html", "HTMLMixedParser");
99 availableParsers.put("freemarker", "FreemarkerParser");
100 availableParsers.put("ftl", "FreemarkerParser");
101 availableParsers.put("groovy", "GroovyParser");
102 availableParsers.put("generic", "HTMLMixedParser");
103 }
104
105
106
107
108 @Override
109 public void drawHtml(Writer out) throws IOException {
110 final Edit control = new Edit(this.getName(), this.getValue());
111 control.setType(this.getConfigValue("type", PropertyType.TYPENAME_STRING));
112 control.setCssClass(CssConstants.CSSCLASS_EDIT);
113 if (this.getConfigValue("saveInfo").equals("false")) {
114 control.setSaveInfo(false);
115 }
116
117 boolean useHighlighter = BooleanUtil.toBoolean(this.getConfigValue("useCodeHighlighter"), true);
118 log.debug("useHighlighter? {}",useHighlighter);
119 if(!useHighlighter){
120 drawSimpleEditor(out, control);
121 return;
122 }
123
124 final String language = this.getConfigValue("language");
125 String parser = null;
126 if(StringUtils.isNotBlank(language)){
127 parser = getAvailableParser(language.trim());
128 if(parser == null){
129 log.warn("No suitable parser found for language {}. Syntax highlighting will not be available. Look at the control's documentation for the supported languages. ", language);
130 drawSimpleEditor(out, control);
131 return;
132 }
133 }
134 drawEditorWithSyntaxHighligher(out, control, parser);
135 }
136
137 private void drawSimpleEditor(Writer out, Edit control) throws IOException {
138 control.setRows(this.getConfigValue("rows", "20"));
139 control.setCssStyles("width", this.getConfigValue("width", "100%"));
140 control.setCssStyles("font-family", "Courier New, monospace");
141 control.setCssStyles("font-size", "14px");
142 if (this.getConfigValue("onchange", null) != null) {
143 control.setEvent("onchange", this.getConfigValue("onchange"));
144 }
145 this.drawHtmlPre(out);
146 out.write(control.getHtml());
147 this.drawHtmlPost(out);
148 }
149
150 private void drawEditorWithSyntaxHighligher(Writer out, Edit control, String parser) throws IOException{
151 final String pathToCodeMirror = this.getRequest().getContextPath() + "/.resources/js/codemirror/";
152 if(parser == null) {
153
154 final NodeData extNodeData = this.getStorageNode().getNodeData("extension");
155
156 if(extNodeData.isExist()){
157 final String ext = extNodeData.getString();
158 parser = getAvailableParser(ext);
159 } else {
160
161 final String template = this.getStorageNode().getMetaData().getTemplate();
162 parser = getAvailableParser(template);
163 }
164 if(parser == null){
165 log.debug("No suitable parser found. Falling back to generic.");
166 parser = getAvailableParser("generic");
167 }
168 }
169
170 final String rows = this.getConfigValue("rows", "20");
171 final String height = String.valueOf(Long.valueOf(rows) * LINE_HEIGHT);
172 control.setRows(height);
173
174 this.drawHtmlPre(out);
175
176 if (getRequest().getAttribute(ATTRIBUTE_CODEMIRROR_LOADED) == null) {
177 out.write("<script type=\"text/javascript\" src=\""+ pathToCodeMirror + "codemirror-min.js\"></script>");
178 getRequest().setAttribute(ATTRIBUTE_CODEMIRROR_LOADED, true);
179 }
180
181 final StringBuilder inlineStyle = new StringBuilder("<style>\n");
182 inlineStyle.append(".CodeMirror-line-numbers {\n");
183 inlineStyle.append("background-color: #eee;\n");
184 inlineStyle.append("text-align: right;\n");
185 inlineStyle.append("font-family: monospace;\n");
186 inlineStyle.append("font-size: 10pt;\n");
187 inlineStyle.append("color: #aaa;\n");
188 inlineStyle.append("line-height: "+ LINE_HEIGHT +"px;\n");
189 inlineStyle.append("padding: .4em;\n");
190 inlineStyle.append("width: 2.2em;\n");
191 inlineStyle.append("</style>\n");
192 out.write(inlineStyle.toString());
193
194 out.write("<div class=\"editorWrapper\" style=\"border: 1px solid #999; padding: 3px;\">");
195 out.write(control.getHtml());
196
197 final boolean lineNumbers = BooleanUtil.toBoolean(this.getConfigValue("lineNumbers"), true);
198 final boolean readOnly = BooleanUtil.toBoolean(this.getConfigValue("readOnly"), false);
199
200 final String editorVar = "editor" + this.getName();
201
202 out.write("\n<script>\n");
203 out.write("MgnlDHTMLUtil.addOnLoad(function(){\n");
204 String codeMirrorEditor = editorVar +" = CodeMirror.fromTextArea(\""+this.getName()+"\", {\n"+
205 " path: \"" + pathToCodeMirror + "\",\n" +
206 " textWrapping: false,\n" +
207 " height: \"" + height + "px\",\n" +
208 " basefiles: [\"codemirror-base.min.js\"],\n" +
209 " parserfile: [\"allinone.js\"],\n" +
210 " stylesheet: [\""+ pathToCodeMirror +"css/jscolors.css\",\""+ pathToCodeMirror +"css/csscolors.css\",\""+
211 pathToCodeMirror +"css/xmlcolors.css\",\""+ pathToCodeMirror +"css/freemarkercolors.css\",\""+ pathToCodeMirror +"css/groovycolors.css\"],\n" +
212 (lineNumbers ? " lineNumbers:true,\n":"") +
213 (readOnly ? " readOnly:true,\n":"") +
214 " initCallback:function(e){ \n"+
215 " e.setParser('"+ parser +"');\n"+
216 " e.focus();\n"+
217 " } \n" +
218 "});\n";
219
220 out.write(codeMirrorEditor);
221
222 out.write(" var b = document.getElementById('mgnlSaveButton');\n");
223 out.write(" var existingOnClick = b.onclick;\n");
224 out.write(" b.onclick=function(){\n");
225
226 out.write(" document.getElementById('cm_hidden_"+ this.getName() + "').value = " + editorVar + ".getCode();\n");
227 out.write(" existingOnClick.apply(this);\n");
228 out.write(" }\n});\n");
229 out.write("</script>\n");
230 out.write("<input type=\"hidden\" name=\"" + this.getName() + "\" id=\"cm_hidden_" + this.getName() + "\" />\n");
231 out.write("</div><!-- closing editorWrapper -->\n");
232
233 this.drawHtmlPost(out);
234 }
235
236 private String getAvailableParser(String language){
237 final String parser = availableParsers.get(language);
238 log.debug("language is {}, parser is {}", language, parser);
239 return parser;
240 }
241 }