001/* 002 * JGrapes Event Driven Framework 003 * Copyright (C) 2017-2018 Michael N. Lipp 004 * 005 * This program is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU Affero General Public License as published by 007 * the Free Software Foundation; either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, but 011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 013 * for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License along 016 * with this program; if not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jgrapes.webconsole.base.events; 020 021import java.io.IOException; 022import java.io.Writer; 023import java.util.Collections; 024import java.util.EnumSet; 025import java.util.Set; 026import java.util.concurrent.ExecutionException; 027import java.util.concurrent.Future; 028import org.jgrapes.webconsole.base.Conlet.RenderMode; 029 030/** 031 * A console command for conlet rendering. Sent to the web console page 032 * for adding or updating a complete web console component representation. 033 * The actual content (the HTML) is passed to the constructor as a 034 * {@link Future}, allowing the content to be evaluated in parallel 035 * to the event handling. 036 * 037 * The content must be valid HTML, usable as inner HTML of a block level 038 * element (typically a `div`). If the root element has an attribute 039 * `data-conlet-title`, its value overrides the default title (the display 040 * name of the conlet type, see {@link AddConletType#displayNames()}). 041 * 042 * The content provided is searched for attributes `data-jgwc-on-load` 043 * and `data-jgwc-on-unload` which must have as value the name of a 044 * function. When the HTML has been loaded or unloaded (i.e. added to 045 * the DOM or removed from the DOM), the respective functions are 046 * invoked with the element containing the attribute as their first 047 * parameter. A second boolean parameter is `true` if the on-load 048 * function is called due to an update of an already existing container. 049 * 050 * The HTML elements of edit dialogs ({@link RenderMode#Edit}) 051 * can have an additional attribute `data-jgwc-on-apply` 052 * which must have as its value the name of a function. This 053 * function is invoked when changes made in the form must be 054 * applied (e.g. before the dialog is closed). 055 */ 056public class RenderConlet extends ConsoleCommand { 057 058 private static final Set<RenderMode> DEFAULT_SUPPORTED 059 = Collections.unmodifiableSet(RenderMode.asSet(RenderMode.Preview)); 060 061 private final String conletType; 062 private final String conletId; 063 private Set<RenderMode> renderAs = RenderMode.asSet(RenderMode.Preview); 064 private Set<RenderMode> supportedModes = DEFAULT_SUPPORTED; 065 private final Future<String> content; 066 067 /** 068 * Creates a new event. 069 * 070 * @param conletType the conlet type 071 * @param conletId the id of the web console component 072 * @param content the content 073 */ 074 public RenderConlet(String conletType, String conletId, 075 Future<String> content) { 076 this.conletType = conletType; 077 this.conletId = conletId; 078 this.content = content; 079 } 080 081 /** 082 * Returns the web console component type as specified on creation. 083 * 084 * @return the type 085 */ 086 public String conletType() { 087 return conletType; 088 } 089 090 /** 091 * Returns the web console component id as specified on creation. 092 * 093 * @return the web console component id 094 */ 095 public String conletId() { 096 return conletId; 097 } 098 099 /** 100 * Set the render mode. The default value is {@link RenderMode#Preview}. 101 * 102 * @param renderMode the render mode to set 103 * @return the event for easy chaining 104 */ 105 public RenderConlet setRenderAs(RenderMode renderMode) { 106 this.renderAs = RenderMode.asSet(renderMode); 107 return this; 108 } 109 110 /** 111 * Set the render mode (including modifier). 112 * 113 * @param renderAs the render mode to use 114 * @return the event for easy chaining 115 */ 116 public RenderConlet setRenderAs(Set<RenderMode> renderAs) { 117 this.renderAs = EnumSet.copyOf(renderAs); 118 return this; 119 } 120 121 /** 122 * Returns the render mode. 123 * 124 * @return the render mode 125 */ 126 public Set<RenderMode> renderAs() { 127 return Collections.unmodifiableSet(renderAs); 128 } 129 130 /** 131 * Set the supported render modes. The default value is 132 * {@link RenderMode#Preview}. 133 * 134 * @param supportedModes the supported render modes to set 135 * @return the event for easy chaining 136 */ 137 public RenderConlet setSupportedModes(Set<RenderMode> supportedModes) { 138 this.supportedModes = supportedModes; 139 return this; 140 } 141 142 /** 143 * Add the given render mode to the supported render modes. 144 * 145 * @param supportedMode the supported render modes to add 146 * @return the event for easy chaining 147 */ 148 public RenderConlet addSupportedMode(RenderMode supportedMode) { 149 if (supportedModes == DEFAULT_SUPPORTED) { 150 supportedModes = EnumSet.copyOf(DEFAULT_SUPPORTED); 151 } 152 supportedModes.add(supportedMode); 153 return this; 154 } 155 156 /** 157 * Returns the supported modes. 158 * 159 * @return the supported modes 160 */ 161 public Set<RenderMode> supportedRenderModes() { 162 return supportedModes; 163 } 164 165 /** 166 * Provides the HTML that displays the web console component 167 * on the page. 168 * 169 * @return the HTML 170 */ 171 public Future<String> content() { 172 return content; 173 } 174 175 /** 176 * Writes the JSON notification to the given writer. 177 * 178 * @param writer the writer 179 * @throws ExecutionException 180 * @throws InterruptedException 181 */ 182 @Override 183 public void emitJson(Writer writer) 184 throws InterruptedException, IOException { 185 try { 186 emitJson(writer, "updateConlet", conletType(), conletId(), 187 renderAs().stream().map(RenderMode::name) 188 .toArray(size -> new String[size]), 189 supportedRenderModes().stream().map(RenderMode::name) 190 .toArray(size -> new String[size]), 191 content().get()); 192 } catch (ExecutionException e) { 193 throw new IOException(e); 194 } 195 } 196}