BrightSide Workbench Full Report + Source Code
ContextComposer.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2021 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.elephant.web;
20 
21 import java.io.File;
22 import java.io.IOException;
23 import java.nio.file.Path;
24 import java.util.logging.Level;
25 import java.util.logging.Logger;
26 import org.turro.string.Strings;
27 import org.turro.auth.Authentication;
28 import org.turro.collections.CollectionUtil;
29 import org.turro.command.Context;
30 import org.turro.diff.Diffs;
31 import org.turro.elephant.context.ElephantContext;
32 import org.turro.elephant.impl.util.FileUtil;
33 import org.turro.elephant.sitemap.SitemapGenerator;
34 import org.turro.elephant.util.Messages;
35 import org.turro.elephant.web.context.WebContext;
36 import org.turro.file.Folder;
37 import org.turro.file.zul.control.RepositoryControl;
38 import org.turro.wiki.parsing.StyledElement;
39 import org.turro.zkoss.dialog.InputDialog;
40 import org.turro.zkoss.dialog.InputField;
41 import org.turro.zkoss.dialog.Windows;
42 import org.turro.zkoss.text.WikiEditor;
43 import org.zkoss.zk.ui.Component;
44 import org.zkoss.zk.ui.HtmlBasedComponent;
45 import org.zkoss.zk.ui.event.Event;
46 import org.zkoss.zk.ui.select.SelectorComposer;
47 import org.zkoss.zk.ui.select.annotation.Listen;
48 import org.zkoss.zk.ui.select.annotation.Wire;
49 import org.zkoss.zk.ui.util.Clients;
50 import org.zkoss.zul.Button;
51 import org.zkoss.zul.Checkbox;
52 import org.zkoss.zul.Include;
53 import org.zkoss.zul.Textbox;
54 import org.zkoss.zul.Toolbarbutton;
55 
60 public class ContextComposer extends SelectorComposer<Component> {
61 
62  private final EditingContext editingContext = new EditingContext();
63 
64  @Wire("#contextTree") private ContextTree contextTree;
65 
66  @Wire("#contextId") private Include contextId;
67  @Wire("#createChild") private Toolbarbutton createChild;
68  @Wire("#removeContext") private Toolbarbutton removeContext;
69 
70  @Wire("#formDetail") private Include formDetail;
71  @Wire("#saveDetail") private Toolbarbutton saveDetail;
72 
73  @Wire("#formPage") private Include formPage;
74  @Wire("#savePage") private Toolbarbutton savePage;
75 
76  @Wire("#formElement") private Include formElement;
77  @Wire("#addAttribute") private Toolbarbutton addAttribute;
78  @Wire("#saveElement") private Toolbarbutton saveElement;
79 
80  @Wire("#base") private StringListbox base;
81  @Wire("#blang") private StringListbox blang;
82  @Wire("#bversion") private StringListbox bversion;
83  @Wire("#removeVersion") private Toolbarbutton removeVersion;
84  @Wire("#diffVersion") private Toolbarbutton diffVersion;
85  @Wire("#autoremove") private Checkbox autoremove;
86  @Wire("#saveContent") private Button saveContent;
87  @Wire("#wikiEditor") private WikiEditor wikiEditor;
88 
89  @Wire("#formRepository") private Include formRepository;
90  @Wire("#formRepository repository") private RepositoryControl repository;
91 
92  @Wire("#formSocial") private Include formSocial;
93 
94  @Listen("onSelect = #contextTree")
95  public void onSelectContext(Event event) {
96  ContextItem contextItem = (ContextItem) contextTree.getSelectedItem();
97  editingContext.setContext(contextItem.getElContext());
98  contextId.invalidate();
99  formDetail.invalidate();
100  formPage.invalidate();
101  formElement.invalidate();
102  formRepository.invalidate();
103  formSocial.invalidate();
104  saveDetail.setDisabled(true);
105  savePage.setDisabled(true);
106  saveElement.setDisabled(true);
107  createChild.setDisabled(contextItem == null);
108  removeContext.setDisabled(contextItem == null);
109  addAttribute.setDisabled(contextItem == null);
110  updateContent();
111  }
112 
113  @Listen("onClick = #saveDetail; onClick = #savePage; onClick = #saveElement")
114  public void onSaveDetail(Event event) {
115  saveAttributes(editingContext.getContext());
118  }
119 
120  @Listen("onClick = #createChild")
121  public void onCreateChild(Event event) {
122  InputDialog.getInput(getPage(),
123  "Child context",
124  new InputField[]{
125  new InputField("Name", "", null, 0) {
126  @Override
127  protected HtmlBasedComponent createEditor() {
128  Textbox tb = new Textbox();
129  tb.setConstraint("/[a-z][a-z0-9\\-]+/: {Start with a lowercase letter, then lowercase letters, numbers or hypens}");
130  return tb;
131  }
132  }
133  }, (Context context) -> {
134  InputField[] fields = (InputField[]) context.get("fields");
135  if(fields.length > 0) {
136  for(InputField f : fields) {
137  if("Name".equals(f.getLabel())) {
138  createAndSelect((String) f.getValue());
139  }
140  }
141  }
142  return null;
143  });
144  }
145 
146  @Listen("onClick = #removeContext")
147  public void onRemoveContext(Event event) {
148  Messages.confirmDeletion().add(editingContext.getContext().getId()).show(() -> {
149  ElContext parent = editingContext.getContext().getParent();
150  if(parent == null) {
151  Clients.showNotification("Cannot remove root");
152  } else {
153  Folder.from(editingContext.getContext().getFile()).remove();
155  contextTree.reload();
156  contextTree.selectPath(parent.getPath());
157  onSelectContext(null);
158  }
159  });
160  }
161 
162  @Listen("onClick = #addAttribute")
163  public void onAddAttribute(Event event) {
164  InputDialog.getInput(getPage(),
165  "Attribute",
166  new InputField[]{
167  new InputField("Name", "", null, 0)
168  }, (Context context) -> {
169  InputField[] fields = (InputField[]) context.get("fields");
170  if(fields.length > 0) {
171  for(InputField f : fields) {
172  if("Name".equals(f.getLabel())) {
173  createAttribute((String) f.getValue());
174  }
175  }
176  }
177  return null;
178  });
179  }
180 
181  @Listen("onSelect = #base; onSelect = #blang")
182  public void onBaseChange(Event event) {
183  updateVersion();
184  }
185 
186  @Listen("onSelect = #bversion")
187  public void onVersionChange(Event event) {
188  File file = editingContext.getContext().getResources().getEditable(
189  base.getObjectValue(), blang.getObjectValue(), bversion.getObjectValue());
190  if(file != null) {
191  try {
192  removeVersion.setDisabled(false);
193  diffVersion.setDisabled(false);
194  wikiEditor.setValue(FileUtil.getContentWithLineBreaks(file));
195  } catch (IOException ex) {
196  Logger.getLogger(ContextComposer.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(null), ex);
197  }
198  } else {
199  wikiEditor.setValue(null);
200  }
201  }
202 
203  @Listen("onClick = #removeVersion")
204  public void onRemoveVersion(Event event) {
205  Messages.confirmDeletion().add(bversion.getObjectValue()).show(() -> {
206  editingContext.removeVersion(base.getObjectValue(),
207  blang.getObjectValue(), bversion.getObjectValue());
208  updateContent();
209  });
210  }
211 
212  @Listen("onClick = #diffVersion")
213  public void onDiffVersion(Event event) {
214  try {
215  File oldFile = editingContext.getContext().getResources().getEditable(
216  base.getObjectValue(), blang.getObjectValue(), bversion.getObjectValue());
217  String oldText = FileUtil.getContentWithLineBreaks(oldFile);
218  File newFile = editingContext.getContext().getResources().getEditable(
219  base.getObjectValue(), blang.getObjectValue(), CollectionUtil.from(bversion.getCollection()).first());
220  String newText = FileUtil.getContentWithLineBreaks(newFile);
221  Windows.showHtml("Diff", Diffs.diff(oldText, newText).efficiency().html());
222  } catch (IOException ex) {
223  Logger.getLogger(ContextComposer.class.getName()).log(Level.SEVERE, null, ex);
224  }
225  }
226 
227  @Listen("onClick = #saveContent")
228  public void onSaveContent(Event event) {
229  editingContext.saveContent(Authentication.getIContact(), base.getObjectValue(),
230  blang.getObjectValue(), wikiEditor.getValue(), wikiEditor.getHtml(),
231  autoremove.isChecked());
232  updateContent();
233  }
234 
235  @Listen("onChange = *; onCheck = *; onSelect = *")
236  public void onChange(Event event) {
237  saveDetail.setDisabled(false);
238  savePage.setDisabled(false);
239  saveElement.setDisabled(false);
240  saveContent.setDisabled(!editingContext.isEditable(base.getObjectValue(), blang.getObjectValue()));
241  wikiEditor.setReadonly(saveContent.isDisabled());
242  if(editingContext.getContext() != null) editingContext.getContext().resetDefaultLocales();
243  }
244 
245  @Override
246  public void doFinally() throws Exception {
247  saveDetail.setDisabled(true);
248  saveDetail.setAutodisable("+self");
249  savePage.setDisabled(true);
250  savePage.setAutodisable("+self");
251  saveElement.setDisabled(true);
252  saveElement.setAutodisable("+self");
253  saveContent.setDisabled(true);
254  saveContent.setAutodisable("+self");
255  createChild.setDisabled(true);
256  removeContext.setDisabled(true);
257  wikiEditor.addResolver(w -> StyledElement.contextuals(w, ElephantContext.getRootWebPath(),
258  editingContext.getContext().getPath(), WebContext.relativeRepository()));
259  }
260 
261  private void saveAttributes(ElContext context) {
262  if(context != null) {
263  WebContext.saveTo(Path.of(context.getPath()), context.getWebContext());
264  saveDetail.setDisabled(true);
265  savePage.setDisabled(true);
266  saveElement.setDisabled(true);
267  }
268  }
269 
270  @Override
271  public void doBeforeComposeChildren(Component comp) throws Exception {
272  comp.setAttribute("edit", editingContext);
273  super.doBeforeComposeChildren(comp);
274  }
275 
276  /* Utils */
277 
278  private void updateContent() {
279  saveContent.setDisabled(true);
280  wikiEditor.setNoTreeRepository(true);
281  wikiEditor.setValue(null);
282  wikiEditor.setFileFolder(editingContext.getContext().getRepositoryPath());
283  wikiEditor.setImageFolder(editingContext.getContext().getRepositoryPath());
284  repository.setPath(editingContext.getPath());
285  base.updateCollection(editingContext.getContext().getResources().getBaseNames());
286  blang.updateCollection(editingContext.getContext().getDefaultLocales());
287  updateVersion();
288  }
289 
290  private void updateVersion() {
291  removeVersion.setDisabled(true);
292  diffVersion.setDisabled(true);
293  bversion.updateCollection(editingContext.getContext().getResources().getVersions(
294  base.getObjectValue(), blang.getObjectValue()));
295  onVersionChange(null);
296  }
297 
298  private void createAndSelect(String child) {
299  if(Strings.isBlank(child)) {
300  Clients.showNotification("Write a valid lowercase context");
301  return;
302  }
303  Path newChild = Path.of(editingContext.getPath(), child);
304  if(WebContext.createFolders(newChild)) {
305  WebContext wc = WebContext.inheritFrom(editingContext.getContext().getWebContext());
306  WebContext.saveTo(newChild, wc);
307  ElContextMap.reset();
308  contextTree.reload();
309  contextTree.selectPath(newChild.toString());
310  onSelectContext(null);
311  } else {
312  Clients.showNotification("Context already exists");
313  }
314  }
315 
316  private void createAttribute(String name) {
317  if(Strings.isBlank(name)) {
318  Clients.showNotification("Write a valid name");
319  return;
320  }
321  editingContext.getContext().getWebContext().getElement().getAttributes().put(name, "");
322  formElement.invalidate();
323  }
324 
325 }
static String getContentWithLineBreaks(File file)
Definition: FileUtil.java:259
static Messages confirmDeletion()
Definition: Messages.java:87
Messages add(String word)
Definition: Messages.java:50
void saveContent(IContact contact, String base, String lang, String wiki, String html, boolean autoremove)
boolean isEditable(String base, String lang)
void removeVersion(String base, String lang, String version)
static void saveTo(Path path, WebContext context)
Map< String, String > getAttributes()
Definition: WebElement.java:56
File getEditable(String base, String lang, String version)
Set< String > getVersions(String base, String lang)
static void getInput(Page page, String title, String label, Object value, String format, int scale, final Command onOk)
static void showHtml(String title, String html)
Definition: Windows.java:126
void setReadonly(boolean value)
void setImageFolder(String folder)
void setValue(String value)
Definition: WikiEditor.java:98
void setNoTreeRepository(boolean noTreeRepository)
void setFileFolder(String folder)
void addResolver(IWikiResolver resolver)