19 package org.turro.zkoss.text;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25 import org.turro.command.Command;
26 import org.turro.command.Context;
27 import org.turro.elephant.context.Application;
28 import org.turro.elephant.context.ElephantContext;
29 import org.turro.elephant.context.IConstructor;
30 import org.turro.elephant.impl.util.FileUtil;
31 import org.turro.elephant.impl.util.Parser;
32 import org.turro.elephant.util.Components;
33 import org.turro.i18n.I_;
34 import org.turro.parser.wiki.WikiProcessors;
35 import org.turro.wiki.WikiParser;
36 import org.turro.wiki.WikiResult;
37 import org.turro.wiki.parsing.IWikiResolver;
38 import org.turro.zkoss.dialog.SelectionDialog;
39 import org.turro.zkoss.input.FileListbox;
40 import org.zkoss.zk.ui.Executions;
41 import org.zkoss.zk.ui.IdSpace;
42 import org.zkoss.zk.ui.annotation.ComponentAnnotation;
43 import org.zkoss.zk.ui.event.Event;
44 import org.zkoss.zk.ui.event.EventListener;
45 import org.zkoss.zk.ui.event.Events;
46 import org.zkoss.zk.ui.event.InputEvent;
47 import org.zkoss.zk.ui.select.Selectors;
48 import org.zkoss.zk.ui.select.annotation.Listen;
49 import org.zkoss.zk.ui.select.annotation.Wire;
50 import org.zkoss.zul.Div;
51 import org.zkoss.zul.Grid;
52 import org.zkoss.zul.Html;
53 import org.zkoss.zul.ListModelArray;
54 import org.zkoss.zul.Menubar;
55 import org.zkoss.zul.Menuitem;
56 import org.zkoss.zul.South;
57 import org.zkoss.zul.Textbox;
63 @ComponentAnnotation({
"value:@ZKBIND(ACCESS=both,SAVE_EVENT=onChange)"})
66 private int selectionStart, selectionEnd;
67 private String imageFolder =
"/", fileFolder =
"/";
68 private boolean readOnlyRepository =
false, noTreeRepository =
false;
69 private final List<IWikiResolver> resolvers =
new ArrayList<>();
71 @Wire
private Menubar wikibar;
73 @Wire
private Grid output;
74 @Wire
private Menuitem elwiki;
75 @Wire
private South outpanel;
78 setSclass(
"wikiEditor");
79 Executions.createComponents(
"/WEB-INF/_zul/bs/comps/editor/wikiInput.zul",
this,
null);
80 Selectors.wireComponents(
this,
this,
false);
81 Selectors.wireEventListeners(
this,
this);
82 wikibox.setWidgetListener(
"onClick",
83 "zAu.send(new zk.Event(this,\"onCaret\",zk(this.$n()).getSelectionRange()+\"\",{toServer:true}));");
84 wikibox.setWidgetListener(
"onBlur",
85 "zAu.send(new zk.Event(this,\"onCaret\",zk(this.$n()).getSelectionRange()+\"\",{toServer:true}));");
86 wikibox.setWidgetListener(
"onSelection",
87 "zAu.send(new zk.Event(this,\"onCaret\",zk(this.$n()).getSelectionRange()+\"\",{toServer:true}));");
88 wikibox.setWidgetListener(
"onChanging",
89 "zAu.send(new zk.Event(this,\"onCaret\",zk(this.$n()).getSelectionRange()+\"\",{toServer:true}));");
90 wikibox.addEventListener(Events.ON_CHANGE,
new EventListener<InputEvent>() {
92 public void onEvent(InputEvent event) throws Exception {
93 Events.postEvent(WikiEditor.this, event);
100 elwiki.setCheckmark(WikiParser.isElWiki(value));
104 return wikibox.getValue();
108 return getHtml(wikibox.getValue(),
false);
112 this.imageFolder = folder;
120 this.fileFolder = folder;
128 return wikibox.isReadonly();
132 wikibox.setReadonly(value);
133 for(Object obj : wikibar.getChildren()) {
134 if(obj instanceof Menuitem) {
135 ((Menuitem) obj).setDisabled(value);
141 return readOnlyRepository;
145 this.readOnlyRepository = readOnlyRepository;
149 return noTreeRepository;
153 this.noTreeRepository = noTreeRepository;
157 return elwiki.isCheckmark();
161 if(resolver !=
null) resolvers.add(resolver);
164 @Listen(
"onCaret = *")
165 public
void onCaret(Event event) {
166 String v[] = ((String) event.getData()).split(
",");
167 selectionStart = Integer.valueOf(v[0]);
168 selectionEnd = Integer.valueOf(v[1]);
171 @Listen(
"onClick = #header1")
172 public
void onHeader1() {
173 insertOnStartLine(
"---+",
new String[] {
174 "---++++",
"---+++",
"---++",
"---+"
178 @Listen(
"onClick = #header2")
179 public
void onHeader2() {
180 insertOnStartLine(
"---++",
new String[] {
181 "---++++",
"---+++",
"---++",
"---+"
185 @Listen(
"onClick = #header3")
186 public
void onHeader3() {
187 insertOnStartLine(
"---+++",
new String[] {
188 "---++++",
"---+++",
"---++",
"---+"
192 @Listen(
"onClick = #header4")
193 public
void onHeader4() {
194 insertOnStartLine(
"---++++",
new String[] {
195 "---++++",
"---+++",
"---++",
"---+"
199 @Listen(
"onClick = #block")
200 public
void onBlock() {
201 insert(
"\n[block]\n",
"\n[/block]\n");
204 @Listen(
"onClick = #span")
205 public
void onSpan() {
206 insert(
"[span]",
"[/span]");
209 @Listen(
"onClick = #note")
210 public
void onNote() {
211 insert(
"\n[note]",
"[/note]\n");
214 @Listen(
"onClick = #startcolumn")
215 public
void onStartColumn() {
216 insert(
"\n[column]\n");
219 @Listen(
"onClick = #endcolumns")
220 public
void onEndColumns() {
221 insert(
"\n[/column]\n");
224 @Listen(
"onClick = #tabulator")
225 public
void onTabulator() {
226 insert(
"\n[tab(Caption1)]\n",
"Content1\n[tab(Caption2)]\nContent2\n[/tab]\n");
229 @Listen(
"onClick = #blind")
230 public
void onBlind() {
231 insert(
"\n[blind(Caption1)]\n",
"Content1\n[blind(Caption2)]\nContent2\n[/blind]\n");
234 @Listen(
"onClick = #bold")
235 public
void onBold() {
237 if(selectionStart == selectionEnd && we.
inside() && !we.
isTag(
"img")) {
238 putAttribute(
"font-weight",
"bold");
240 insert(
"**",
"**",
true);
244 @Listen(
"onClick = #italic")
245 public
void onItalic() {
247 if(selectionStart == selectionEnd && we.
inside() && !we.
isTag(
"img")) {
248 putAttribute(
"font-style",
"italic");
250 insert(
"__",
"__",
true);
254 @Listen(
"onClick = #regular")
255 public
void onRegular() {
256 insert(
"==",
"==",
true);
259 @Listen(
"onClick = #toWiki")
260 public
void onToWiki() {
261 String v = wikibox.getValue();
263 wikibox.setSelectedText(0, v.length(), w,
false);
264 wikibox.setSelectionRange(0, 0);
265 wikibox.setFocus(
true);
266 Events.postEvent(
new InputEvent(
"onChange",
this, wikibox.getValue(),
null));
269 @Listen(
"onClick = #preview")
270 public
void onPreview() {
272 div.setStyle(
"overflow:auto;");
273 Html html =
new Html(getHtml(wikibox.getValue(),
true));
274 div.appendChild(html);
278 @Listen(
"onClick = #html")
279 public
void onHtml() {
281 div.setSclass(
"wikiEditor");
282 Textbox html =
new Textbox(getHtml(wikibox.getValue(),
false));
283 html.setSclass(
"wikiBox");
284 html.setReadonly(
true);
285 html.setMultiline(
true);
288 div.appendChild(html);
292 @Listen(
"onClick = #startwiki")
293 public
void onStartWiki() {
297 @Listen(
"onClick = #stopwiki")
298 public
void onStopWiki() {
299 insert(
"\n$no_wiki\n");
302 @Listen(
"onClick = #startjava")
303 public
void onStartJava() {
307 @Listen(
"onClick = #stopjava")
308 public
void onStopJava() {
309 insert(
"\n$no_java\n");
312 @Listen(
"onClick = #startxml")
313 public
void onStartXml() {
317 @Listen(
"onClick = #stopxml")
318 public
void onStopXml() {
319 insert(
"\n$no_xml\n");
322 @Listen(
"onClick = #alignleft")
323 public
void onAlignLeft() {
324 putAttribute(
"text-align",
"left");
327 @Listen(
"onClick = #aligncenter")
328 public
void onAlignCenter() {
329 putAttribute(
"text-align",
"center");
332 @Listen(
"onClick = #alignright")
333 public
void onAlignRight() {
334 putAttribute(
"text-align",
"right");
337 @Listen(
"onClick = #alignjustify")
338 public
void onAlignJustify() {
339 putAttribute(
"text-align",
"justify");
342 @Listen(
"onClick = #floatleft")
343 public
void onFloatLeft() {
344 putAttribute(
"float",
"left");
347 @Listen(
"onClick = #floatright")
348 public
void onFloatright() {
349 putAttribute(
"float",
"right");
352 @Listen(
"onClick = #ullist")
353 public
void onUlList() {
354 insertOnStartLine(
" * ",
" 1 ");
357 @Listen(
"onClick = #ollist")
358 public
void onOlList() {
359 insertOnStartLine(
" 1 ",
" * ");
362 @Listen(
"onClick = #thl")
363 public
void onThl() {
367 @Listen(
"onClick = #thr")
368 public
void onThr() {
372 @Listen(
"onClick = #trl")
373 public
void onTrl() {
377 @Listen(
"onClick = #trr")
378 public
void onTrr() {
382 @Listen(
"onClick = #tcl")
383 public
void onTcl() {
387 @Listen(
"onClick = #tcr")
388 public
void onTcr() {
392 @Listen(
"onClick = #tet")
393 public
void onTet() {
397 @Listen(
"onClick = #eraser")
398 public
void onEraser() {
402 @Listen(
"onChange = #color")
403 public
void onColor(InputEvent event) {
404 putAttribute(
"color", event.getValue());
407 @Listen(
"onChange = #background")
408 public
void onBackground(InputEvent event) {
409 putAttribute(
"background-color", event.getValue());
412 @Listen(
"onClick = #link")
413 public
void onLink() {
415 if(!we.
isTag(
"link")) {
424 public Object execute(Context context) {
425 Link link = (
Link) context.get(
"component");
427 wikibox.setSelectionRange(selectionStart, selectionStart);
428 wikibox.setFocus(
true);
429 Events.postEvent(
new InputEvent(
"onChange",
WikiEditor.this, wikibox.
getValue(),
null));
436 @Listen(
"onClick = #image")
437 public
void onImage() {
449 public Object execute(Context context) {
451 wikibox.setSelectionRange(selectionStart, selectionStart);
452 wikibox.setFocus(
true);
453 Events.postEvent(
new InputEvent(
"onChange",
WikiEditor.this, wikibox.
getValue(),
null));
460 @Listen(
"onClick = #template")
461 public
void onTemplate() {
468 fl.addEventListener(Events.ON_DOUBLE_CLICK, (Event event) -> {
469 insert(FileUtil.getContentWithLineBreaks(fl.getObjectValue()));
470 Events.postEvent(new Event(Events.ON_CLOSE, Components.from(fl).parent(SelectionDialog.class)));
473 if(fl.getObjectValue() != null) {
474 wikibox.setFocus(true);
475 Events.postEvent(new InputEvent(
"onChange", WikiEditor.this, wikibox.getValue(), null));
482 @Listen(
"onClick = #snippet")
483 public
void onSnippet() {
490 fl.addEventListener(Events.ON_DOUBLE_CLICK, (Event event) -> {
491 insert(FileUtil.getContentWithLineBreaks(fl.getObjectValue()));
492 Events.postEvent(new Event(Events.ON_CLOSE, Components.from(fl).parent(SelectionDialog.class)));
495 if(fl.getObjectValue() != null) {
496 wikibox.setFocus(true);
497 Events.postEvent(new InputEvent(
"onChange", WikiEditor.this, wikibox.getValue(), null));
504 @Listen(
"onClick = #elwiki")
505 public
void onElWiki() {
506 elwiki.setCheckmark(!elwiki.isCheckmark());
509 private void insert(String
string) {
510 int start = selectionStart;
511 wikibox.setSelectedText(start, start,
string,
false);
512 start +=
string.length();
513 wikibox.setSelectionRange(start, start);
514 wikibox.setFocus(
true);
515 Events.postEvent(
new InputEvent(
"onChange",
this, wikibox.getValue(),
null));
518 private void insert(String startTag, String endTag) {
519 insert(startTag, endTag,
false);
522 private void insert(String startTag, String endTag,
boolean singleLine) {
523 int start = selectionStart, end = selectionEnd;
524 String value = wikibox.getValue();
526 for(
int i = start; i < end; i++) {
527 if(value.charAt(i) ==
'\n') {
533 wikibox.setSelectedText(start, start, startTag,
false);
534 start += startTag.length();
535 end += startTag.length();
536 wikibox.setSelectedText(end, end, endTag,
false);
537 wikibox.setSelectionRange(start, start);
538 wikibox.setFocus(
true);
539 Events.postEvent(
new InputEvent(
"onChange",
this, wikibox.getValue(),
null));
542 private void putAttribute(String key, String value) {
543 WikiElement we =
new WikiElement(selectionStart, selectionEnd, wikibox, WikiElement.NON_BLOCK_ELEMENTS);
544 we.getAttributes().put(key, value);
546 wikibox.setSelectionRange(selectionStart, selectionStart);
547 wikibox.setFocus(
true);
548 Events.postEvent(
new InputEvent(
"onChange",
this, wikibox.getValue(),
null));
551 private void removeAttributes() {
552 WikiElement we =
new WikiElement(selectionStart, selectionEnd, wikibox, WikiElement.NON_BLOCK_ELEMENTS);
553 we.removeValuedAttributes();
555 wikibox.setSelectionRange(selectionStart, selectionStart);
556 wikibox.setFocus(
true);
557 Events.postEvent(
new InputEvent(
"onChange",
this, wikibox.getValue(),
null));
560 private void insertOnStartLine(String value) {
561 insertOnStartLine(value, value);
564 private void insertOnStartLine(String value, String replacement) {
565 insertOnStartLine(value,
new String[] { value, replacement });
568 private void insertOnStartLine(String value, String[] replacement) {
569 int start = selectionStart, end = selectionEnd;
570 String text = wikibox.getValue();
572 for(
int c = start - 1; c >= 0; c--) {
573 if(text.charAt(c) ==
'\n') {
574 int shift = killReplacements(text, c + 1, replacement);
577 wikibox.setSelectedText(c + 1, c + 1, value,
false);
578 start += value.length();
579 end += value.length();
582 int shift = killReplacements(text, c, replacement);
585 wikibox.setSelectedText(c, c, value,
false);
586 start += value.length();
587 end += value.length();
591 text = wikibox.getValue();
593 for(
int c = start; c < end; c++) {
594 if(text.charAt(c) ==
'\n') {
595 int shift = killReplacements(text, c + 1, replacement);
597 wikibox.setSelectedText(c + 1, c + 1, value,
false);
598 end += value.length();
599 text = wikibox.getValue();
601 int shift = killReplacements(text, c, replacement);
603 wikibox.setSelectedText(c, c, value,
false);
604 end += value.length();
605 text = wikibox.getValue();
608 wikibox.setSelectionRange(start, start);
609 wikibox.setFocus(
true);
610 Events.postEvent(
new InputEvent(
"onChange",
this, wikibox.getValue(),
null));
613 private int killReplacements(String text,
int c, String[] replacement) {
615 for(String r : replacement) {
616 if(text.substring(c).startsWith(r)) {
617 wikibox.setSelectedText(c, c + r.length(),
"",
false);
625 private void setWiki(String source) {
626 elwiki.setCheckmark(
false);
627 wikibox.setValue(source);
630 private String getHtml(String source,
boolean preview) {
631 IConstructor constructor = Application.getApplication().getConstructor();
633 output.setModel(
new ListModelArray(Collections.EMPTY_LIST));
634 elwiki.setCheckmark(elwiki.isCheckmark() || WikiParser.isElWiki(source));
635 if(elwiki.isCheckmark()) {
636 WikiResult result = WikiParser.instance()
637 .onProcessor(wmacro -> WikiProcessors.instance().constructor(constructor).resolve(wmacro))
638 .addResolvers(resolvers)
639 .parse(wikibox.getValue());
640 htmlStr = result.getHtml();
641 if(!result.getErrors().isEmpty()) {
642 output.setModel(
new ListModelArray<>(result.getErrors()));
643 outpanel.setOpen(
true);
645 outpanel.setOpen(
false);
648 Parser parser =
new Parser(
"$wiki\n" + wikibox.getValue());
649 parser.setResolver(w -> {
650 for(IWikiResolver resolver : resolvers) {
651 w = resolver.apply(w);
655 htmlStr = parser.parse(constructor);
657 return (preview ? styleSheets() :
"") + htmlStr;
660 private String styleSheets() {
661 return "<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
662 ElephantContext.getRootWebPath() +
"/_internal/css/elephant-theme.css" +
static String getRealPath(String path)
static String toWiki(String text)
static String get(String msg)
static void showComponent(Page page, String title, Component component, String width, String height, final Command command)
void setReadOnlyRepository(boolean readOnlyRepository)
void setFileFolder(String fileFolder)
void setNoTreeRepository(boolean noTreeRepository)
static final String IMAGE_FILTER
void setFilter(String filter)
void selectFolder(String folder)
void setNoTreeRepository(boolean noTreeRepository)
void setReadOnlyRepository(boolean readOnlyRepository)
boolean isReadOnlyRepository()
void setReadonly(boolean value)
void setImageFolder(String folder)
void setValue(String value)
boolean isNoTreeRepository()
void setNoTreeRepository(boolean noTreeRepository)
void setFileFolder(String folder)
void setReadOnlyRepository(boolean readOnlyRepository)
void addResolver(IWikiResolver resolver)
void forgetAndCreate(String newTag)
boolean isTag(String tag)
static final String[] NON_BLOCK_ELEMENTS