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.HashSet; 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 */ 056@SuppressWarnings("PMD.LinguisticNaming") 057public class RenderConlet extends ConsoleCommand { 058 059 private static final Set<RenderMode> DEFAULT_SUPPORTED 060 = Collections.unmodifiableSet(RenderMode.asSet(RenderMode.Preview)); 061 062 private final String conletType; 063 private final String conletId; 064 private Set<RenderMode> renderAs = RenderMode.asSet(RenderMode.Preview); 065 private Set<RenderMode> supportedModes = DEFAULT_SUPPORTED; 066 private final Future<String> content; 067 068 /** 069 * Creates a new event. 070 * 071 * @param conletType the conlet type 072 * @param conletId the id of the web console component 073 * @param content the content 074 */ 075 public RenderConlet(String conletType, String conletId, 076 Future<String> content) { 077 this.conletType = conletType; 078 this.conletId = conletId; 079 this.content = content; 080 } 081 082 /** 083 * Returns the web console component type as specified on creation. 084 * 085 * @return the type 086 */ 087 public String conletType() { 088 return conletType; 089 } 090 091 /** 092 * Returns the web console component id as specified on creation. 093 * 094 * @return the web console component id 095 */ 096 public String conletId() { 097 return conletId; 098 } 099 100 /** 101 * Set the render mode. The default value is {@link RenderMode#Preview}. 102 * 103 * @param renderMode the render mode to set 104 * @return the event for easy chaining 105 */ 106 public RenderConlet setRenderAs(RenderMode renderMode) { 107 this.renderAs = RenderMode.asSet(renderMode); 108 return this; 109 } 110 111 /** 112 * Set the render mode (including modifier). 113 * 114 * @param renderAs the render mode to use 115 * @return the event for easy chaining 116 */ 117 public RenderConlet setRenderAs(Set<RenderMode> renderAs) { 118 this.renderAs = new HashSet<>(renderAs); 119 return this; 120 } 121 122 /** 123 * Returns the render mode. 124 * 125 * @return the render mode 126 */ 127 public Set<RenderMode> renderAs() { 128 return Collections.unmodifiableSet(renderAs); 129 } 130 131 /** 132 * Set the supported render modes. The default value is 133 * {@link RenderMode#Preview}. 134 * 135 * @param supportedModes the supported render modes to set 136 * @return the event for easy chaining 137 */ 138 public RenderConlet setSupportedModes(Set<RenderMode> supportedModes) { 139 this.supportedModes = supportedModes; 140 return this; 141 } 142 143 /** 144 * Add the given render mode to the supported render modes. 145 * 146 * @param supportedMode the supported render modes to add 147 * @return the event for easy chaining 148 */ 149 public RenderConlet addSupportedMode(RenderMode supportedMode) { 150 if (supportedModes == DEFAULT_SUPPORTED) { // NOPMD, check identity 151 supportedModes = new HashSet<>(DEFAULT_SUPPORTED); 152 } 153 supportedModes.add(supportedMode); 154 return this; 155 } 156 157 /** 158 * Returns the supported modes. 159 * 160 * @return the supported modes 161 */ 162 public Set<RenderMode> supportedRenderModes() { 163 return supportedModes; 164 } 165 166 /** 167 * Provides the HTML that displays the web console component 168 * on the page. 169 * 170 * @return the HTML 171 */ 172 public Future<String> content() { 173 return content; 174 } 175 176 /** 177 * Writes the JSON notification to the given writer. 178 * 179 * @param writer the writer 180 * @throws ExecutionException 181 * @throws InterruptedException 182 */ 183 @Override 184 public void emitJson(Writer writer) 185 throws InterruptedException, IOException { 186 try { 187 emitJson(writer, "updateConlet", conletType(), conletId(), 188 renderAs().stream().map(RenderMode::name) 189 .toArray(size -> new String[size]), 190 supportedRenderModes().stream().map(RenderMode::name) 191 .toArray(size -> new String[size]), 192 content().get()); 193 } catch (ExecutionException e) { 194 throw new IOException(e); 195 } 196 } 197}