BrightSide Workbench Full Report + Source Code
WikiEditor.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2015 Lluis TurrĂ³ Cutiller <http://www.turro.org/>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 package org.turro.zkoss.text;
20 
21 import org.apache.commons.chain.Command;
22 import org.apache.commons.chain.Context;
27 import org.zkoss.zk.ui.Executions;
28 import org.zkoss.zk.ui.IdSpace;
29 import org.zkoss.zk.ui.event.Event;
30 import org.zkoss.zk.ui.event.EventListener;
31 import org.zkoss.zk.ui.event.Events;
32 import org.zkoss.zk.ui.event.InputEvent;
33 import org.zkoss.zk.ui.select.Selectors;
34 import org.zkoss.zk.ui.select.annotation.Listen;
35 import org.zkoss.zk.ui.select.annotation.Wire;
36 import org.zkoss.zul.Div;
37 import org.zkoss.zul.Html;
38 import org.zkoss.zul.Menubar;
39 import org.zkoss.zul.Menuitem;
40 
45 public class WikiEditor extends Div implements IdSpace {
46 
47  private int selectionStart, selectionEnd;
48  private String imageFolder = "/", fileFolder = "/";
49  private boolean readOnlyRepository = false, noTreeRepository = false;
50 
51  @Wire private Menubar wikibar;
52  @Wire private WikiTextbox wikibox;
53 
54  public WikiEditor() {
55  Executions.createComponents("/WEB-INF/_zul/bs/comps/editor/wikiInput.zul", this, null);
56  Selectors.wireComponents(this, this, false);
57  Selectors.wireEventListeners(this, this);
58  wikibox.setWidgetListener("onClick",
59  "zAu.send(new zk.Event(this,\"onCaret\",zk(this.$n()).getSelectionRange()+\"\",{toServer:true}));");
60  wikibox.setWidgetListener("onBlur",
61  "zAu.send(new zk.Event(this,\"onCaret\",zk(this.$n()).getSelectionRange()+\"\",{toServer:true}));");
62  wikibox.setWidgetListener("onSelection",
63  "zAu.send(new zk.Event(this,\"onCaret\",zk(this.$n()).getSelectionRange()+\"\",{toServer:true}));");
64  wikibox.setWidgetListener("onChanging",
65  "zAu.send(new zk.Event(this,\"onCaret\",zk(this.$n()).getSelectionRange()+\"\",{toServer:true}));");
66  wikibox.addEventListener(Events.ON_CHANGE, new EventListener<InputEvent>() {
67  @Override
68  public void onEvent(InputEvent event) throws Exception {
69  Events.postEvent(WikiEditor.this, event);
70  }
71  });
72  }
73 
74  public void setValue(String value) {
75  wikibox.setValue(value);
76  }
77 
78  public String getValue() {
79  return wikibox.getValue();
80  }
81 
82  public void setImageFolder(String folder) {
83  this.imageFolder = folder;
84  }
85 
86  public String getImageFolder() {
87  return imageFolder;
88  }
89 
90  public void setFileFolder(String folder) {
91  this.fileFolder = folder;
92  }
93 
94  public String getFileFolder() {
95  return fileFolder;
96  }
97 
98  public boolean isReadonly() {
99  return wikibox.isReadonly();
100  }
101 
102  public void setReadonly(boolean value) {
103  wikibox.setReadonly(value);
104  for(Object obj : wikibar.getChildren()) {
105  if(obj instanceof Menuitem) {
106  ((Menuitem) obj).setDisabled(value);
107  }
108  }
109  }
110 
111  public boolean isReadOnlyRepository() {
112  return readOnlyRepository;
113  }
114 
115  public void setReadOnlyRepository(boolean readOnlyRepository) {
116  this.readOnlyRepository = readOnlyRepository;
117  }
118 
119  public boolean isNoTreeRepository() {
120  return noTreeRepository;
121  }
122 
123  public void setNoTreeRepository(boolean noTreeRepository) {
124  this.noTreeRepository = noTreeRepository;
125  }
126 
127  @Listen("onCaret = *")
128  public void onCaret(Event event) {
129  String v[] = ((String) event.getData()).split(",");
130  selectionStart = Integer.valueOf(v[0]);
131  selectionEnd = Integer.valueOf(v[1]);
132  }
133 
134  @Listen("onClick = #header1")
135  public void onHeader1() {
136  insertOnStartLine("---+", new String[] {
137  "---++++", "---+++", "---++", "---+"
138  });
139  }
140 
141  @Listen("onClick = #header2")
142  public void onHeader2() {
143  insertOnStartLine("---++", new String[] {
144  "---++++", "---+++", "---++", "---+"
145  });
146  }
147 
148  @Listen("onClick = #header3")
149  public void onHeader3() {
150  insertOnStartLine("---+++", new String[] {
151  "---++++", "---+++", "---++", "---+"
152  });
153  }
154 
155  @Listen("onClick = #header4")
156  public void onHeader4() {
157  insertOnStartLine("---++++", new String[] {
158  "---++++", "---+++", "---++", "---+"
159  });
160  }
161 
162  @Listen("onClick = #block")
163  public void onBlock() {
164  insert("\n[block]\n", "\n[/block]\n");
165  }
166 
167  @Listen("onClick = #span")
168  public void onSpan() {
169  insert("[span]", "[/span]");
170  }
171 
172  @Listen("onClick = #note")
173  public void onNote() {
174  insert("\n[note]", "[/note]\n");
175  }
176 
177  @Listen("onClick = #startcolumn")
178  public void onStartColumn() {
179  insert("\n[column]\n");
180  }
181 
182  @Listen("onClick = #endcolumns")
183  public void onEndColumns() {
184  insert("\n[/column]\n");
185  }
186 
187  @Listen("onClick = #tabulator")
188  public void onTabulator() {
189  insert("\n[tab(Caption1)]\n","Content1\n[tab(Caption2)]\nContent2\n[/tab]\n");
190  }
191 
192  @Listen("onClick = #blind")
193  public void onBlind() {
194  insert("\n[blind(Caption1)]\n","Content1\n[blind(Caption2)]\nContent2\n[/blind]\n");
195  }
196 
197  @Listen("onClick = #bold")
198  public void onBold() {
199  WikiElement we = new WikiElement(selectionStart, selectionEnd, wikibox, WikiElement.NON_BLOCK_ELEMENTS);
200  if(selectionStart == selectionEnd && we.inside() && !we.isTag("img")) {
201  putAttribute("font-weight", "bold");
202  } else {
203  insert("**","**", true);
204  }
205  }
206 
207  @Listen("onClick = #italic")
208  public void onItalic() {
209  WikiElement we = new WikiElement(selectionStart, selectionEnd, wikibox, WikiElement.NON_BLOCK_ELEMENTS);
210  if(selectionStart == selectionEnd && we.inside() && !we.isTag("img")) {
211  putAttribute("font-style", "italic");
212  } else {
213  insert("__","__", true);
214  }
215  }
216 
217  @Listen("onClick = #regular")
218  public void onRegular() {
219  insert("==","==", true);
220  }
221 
222  @Listen("onClick = #preview")
223  public void onPreview() {
224  Div div = new Div();
225  div.setStyle("overflow:auto;");
226  Html html = new Html(new Parser("$wiki\n" + wikibox.getValue()).parse(Application.getApplication().getConstructor()));
227  div.appendChild(html);
228  SelectionDialog.showComponent(getPage(), ElLabel.getLabel("lPreview"), div, "800px", "80%", null);
229  }
230 
231  @Listen("onClick = #startwiki")
232  public void onStartWiki() {
233  insert("\n$wiki\n");
234  }
235 
236  @Listen("onClick = #stopwiki")
237  public void onStopWiki() {
238  insert("\n$no_wiki\n");
239  }
240 
241  @Listen("onClick = #startjava")
242  public void onStartJava() {
243  insert("\n$java\n");
244  }
245 
246  @Listen("onClick = #stopjava")
247  public void onStopJava() {
248  insert("\n$no_java\n");
249  }
250 
251  @Listen("onClick = #startxml")
252  public void onStartXml() {
253  insert("\n$xml\n");
254  }
255 
256  @Listen("onClick = #stopxml")
257  public void onStopXml() {
258  insert("\n$no_xml\n");
259  }
260 
261  @Listen("onClick = #alignleft")
262  public void onAlignLeft() {
263  putAttribute("text-align", "left");
264  }
265 
266  @Listen("onClick = #aligncenter")
267  public void onAlignCenter() {
268  putAttribute("text-align", "center");
269  }
270 
271  @Listen("onClick = #alignright")
272  public void onAlignRight() {
273  putAttribute("text-align", "right");
274  }
275 
276  @Listen("onClick = #alignjustify")
277  public void onAlignJustify() {
278  putAttribute("text-align", "justify");
279  }
280 
281  @Listen("onClick = #floatleft")
282  public void onFloatLeft() {
283  putAttribute("float", "left");
284  }
285 
286  @Listen("onClick = #floatright")
287  public void onFloatright() {
288  putAttribute("float", "right");
289  }
290 
291  @Listen("onClick = #ullist")
292  public void onUlList() {
293  insertOnStartLine(" * ", " 1 ");
294  }
295 
296  @Listen("onClick = #ollist")
297  public void onOlList() {
298  insertOnStartLine(" 1 ", " * ");
299  }
300 
301  @Listen("onClick = #thl")
302  public void onThl() {
303  insert("\n||>");
304  }
305 
306  @Listen("onClick = #thr")
307  public void onThr() {
308  insert("\n||<");
309  }
310 
311  @Listen("onClick = #trl")
312  public void onTrl() {
313  insert("\n|->");
314  }
315 
316  @Listen("onClick = #trr")
317  public void onTrr() {
318  insert("\n|-<");
319  }
320 
321  @Listen("onClick = #tcl")
322  public void onTcl() {
323  insert("\n|>");
324  }
325 
326  @Listen("onClick = #tcr")
327  public void onTcr() {
328  insert("\n|<");
329  }
330 
331  @Listen("onClick = #tet")
332  public void onTet() {
333  insert("\n-||");
334  }
335 
336  @Listen("onClick = #eraser")
337  public void onEraser() {
338  removeAttributes();
339  }
340 
341  @Listen("onChange = #color")
342  public void onColor(InputEvent event) {
343  putAttribute("color", event.getValue());
344  }
345 
346  @Listen("onChange = #background")
347  public void onBackground(InputEvent event) {
348  putAttribute("background-color", event.getValue());
349  }
350 
351  @Listen("onClick = #link")
352  public void onLink() {
353  WikiElement we = new WikiElement(selectionStart, selectionEnd, wikibox);
354  if(!we.isTag("link")) {
355  we.forgetAndCreate("link");
356  }
357  Link link = new Link(we);
358  link.setFileFolder(fileFolder);
359  link.setReadOnlyRepository(readOnlyRepository);
360  link.setNoTreeRepository(noTreeRepository);
361  SelectionDialog.getComponent(Executions.getCurrent().getDesktop().getFirstPage(), "Link", link, "500px", null, new Command() {
362  @Override
363  public boolean execute(Context context) throws Exception {
364  Link link = (Link) context.get("component");
365  if(link != null && link.renderResult()) {
366  wikibox.setSelectionRange(selectionStart, selectionStart);
367  wikibox.setFocus(true);
368  Events.postEvent(new InputEvent("onChange", WikiEditor.this, wikibox.getValue(), null));
369  }
370  return Command.PROCESSING_COMPLETE;
371  }
372  });
373  }
374 
375  @Listen("onClick = #image")
376  public void onImage() {
377  WikiElement we = new WikiElement(selectionStart, wikibox, "img");
378 // if(!we.isTag("img")) {
379 // we.forgetAndCreate("img");
380 // }
381  final RepositoryWalker repositories = new RepositoryWalker(we);
382  repositories.selectFolder(imageFolder);
384  repositories.setReadOnlyRepository(readOnlyRepository);
385  repositories.setNoTreeRepository(noTreeRepository);
386  SelectionDialog.showComponent(getPage(), ElLabel.getLabel("lRepository"), repositories, "90%", "90%", new Command() {
387  @Override
388  public boolean execute(Context context) throws Exception {
389  if(repositories.renderResult()) {
390  wikibox.setSelectionRange(selectionStart, selectionStart);
391  wikibox.setFocus(true);
392  Events.postEvent(new InputEvent("onChange", WikiEditor.this, wikibox.getValue(), null));
393  }
394  return Command.PROCESSING_COMPLETE;
395  }
396  });
397  }
398 
399  private void insert(String string) {
400  int start = selectionStart;
401  wikibox.setSelectedText(start, start, string, false);
402  start += string.length();
403  wikibox.setSelectionRange(start, start);
404  wikibox.setFocus(true);
405  Events.postEvent(new InputEvent("onChange", this, wikibox.getValue(), null));
406  }
407 
408  private void insert(String startTag, String endTag) {
409  insert(startTag, endTag, false);
410  }
411 
412  private void insert(String startTag, String endTag, boolean singleLine) {
413  int start = selectionStart, end = selectionEnd;
414  String value = wikibox.getValue();
415  if(singleLine) {
416  for(int i = start; i < end; i++) {
417  if(value.charAt(i) == '\n') {
418  end = i - 1;
419  break;
420  }
421  }
422  }
423  wikibox.setSelectedText(start, start, startTag, false);
424  start += startTag.length();
425  end += startTag.length();
426  wikibox.setSelectedText(end, end, endTag, false);
427  wikibox.setSelectionRange(start, start);
428  wikibox.setFocus(true);
429  Events.postEvent(new InputEvent("onChange", this, wikibox.getValue(), null));
430  }
431 
432  private void putAttribute(String key, String value) {
433  WikiElement we = new WikiElement(selectionStart, selectionEnd, wikibox, WikiElement.NON_BLOCK_ELEMENTS);
434  we.getAttributes().put(key, value);
435  we.render();
436  wikibox.setSelectionRange(selectionStart, selectionStart);
437  wikibox.setFocus(true);
438  Events.postEvent(new InputEvent("onChange", this, wikibox.getValue(), null));
439  }
440 
441  private void removeAttributes() {
442  WikiElement we = new WikiElement(selectionStart, selectionEnd, wikibox, WikiElement.NON_BLOCK_ELEMENTS);
444  we.render();
445  wikibox.setSelectionRange(selectionStart, selectionStart);
446  wikibox.setFocus(true);
447  Events.postEvent(new InputEvent("onChange", this, wikibox.getValue(), null));
448  }
449 
450  private void insertOnStartLine(String value) {
451  insertOnStartLine(value, value);
452  }
453 
454  private void insertOnStartLine(String value, String replacement) {
455  insertOnStartLine(value, new String[] { value, replacement });
456  }
457 
458  private void insertOnStartLine(String value, String[] replacement) {
459  int start = selectionStart, end = selectionEnd;
460  String text = wikibox.getValue();
461  // Start with first line
462  for(int c = start - 1; c >= 0; c--) {
463  if(text.charAt(c) == '\n') {
464  int shift = killReplacements(text, c + 1, replacement);
465  start += shift;
466  end += shift;
467  wikibox.setSelectedText(c + 1, c + 1, value, false);
468  start += value.length();
469  end += value.length();
470  break;
471  } else if(c == 0) {
472  int shift = killReplacements(text, c, replacement);
473  start += shift;
474  end += shift;
475  wikibox.setSelectedText(c, c, value, false);
476  start += value.length();
477  end += value.length();
478  break;
479  }
480  }
481  text = wikibox.getValue();
482  // Walk through selection
483  for(int c = start; c < end; c++) {
484  if(text.charAt(c) == '\n') {
485  int shift = killReplacements(text, c + 1, replacement);
486  end += shift;
487  wikibox.setSelectedText(c + 1, c + 1, value, false);
488  end += value.length();
489  text = wikibox.getValue();
490  } else if(c == 0) {
491  int shift = killReplacements(text, c, replacement);
492  end += shift;
493  wikibox.setSelectedText(c, c, value, false);
494  end += value.length();
495  text = wikibox.getValue();
496  }
497  }
498  wikibox.setSelectionRange(start, start);
499  wikibox.setFocus(true);
500  Events.postEvent(new InputEvent("onChange", this, wikibox.getValue(), null));
501  }
502 
503  private int killReplacements(String text, int c, String[] replacement) {
504  int shift = 0;
505  for(String r : replacement) {
506  if(text.substring(c).startsWith(r)) {
507  wikibox.setSelectedText(c, c + r.length(), "", false);
508  shift -= r.length();
509  break;
510  }
511  }
512  return shift;
513  }
514 
515 }
static final String [] NON_BLOCK_ELEMENTS
HashMap< String, String > getAttributes()
void onBackground(InputEvent event)
void setReadOnlyRepository(boolean readOnlyRepository)
static void showComponent(Page page, String title, Component component, String width, String height, final Command command)
void setFileFolder(String folder)
Definition: WikiEditor.java:90
static String getLabel(String key)
Definition: ElLabel.java:36
void forgetAndCreate(String newTag)
void setReadonly(boolean value)
void setReadOnlyRepository(boolean readOnlyRepository)
void onColor(InputEvent event)
void setNoTreeRepository(boolean noTreeRepository)
void setValue(String value)
Definition: WikiEditor.java:74
void setNoTreeRepository(boolean noTreeRepository)
void setImageFolder(String folder)
Definition: WikiEditor.java:82