001// Copyright 2023 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.corelib.components;
016
017import org.apache.tapestry5.BindingConstants;
018import org.apache.tapestry5.ComponentResources;
019import org.apache.tapestry5.MarkupWriter;
020import org.apache.tapestry5.annotations.Environmental;
021import org.apache.tapestry5.annotations.Parameter;
022import org.apache.tapestry5.annotations.Property;
023import org.apache.tapestry5.commons.Messages;
024import org.apache.tapestry5.ioc.annotations.Inject;
025import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
026import org.apache.tapestry5.services.javascript.JavaScriptSupport;
027
028/**
029 * Component that renders a <a href="http://graphviz.org">Graphviz</a> graph using
030 * <a href="https://www.npmjs.com/package/@hpcc-js/wasm">@hpcc-js/wasm</a>. It's mostly 
031 * intended to be used internally at Tapestry, hence the limited set of options.
032 * 
033 * @tapestrydoc
034 * @since 5.8.3
035 */
036public class Graphviz
037{
038    
039    /**
040     * A Graphviz graph described in its DOT language.
041     */
042    @Parameter(required = true, allowNull = false)
043    @Property
044    private String value;
045    
046    /**
047     * Defines whether a link to download the graph as an SVG file should be provided.
048     */
049    @Parameter(defaultPrefix = BindingConstants.LITERAL, value = "false")
050    private boolean showDownloadLink;
051
052    /**
053     * Defines whether a the Graphviz source should be shown.
054     */
055    @Parameter(defaultPrefix = BindingConstants.LITERAL, value = "false")
056    private boolean showSource;
057
058    @Environmental
059    private JavaScriptSupport javaScriptSupport;
060    
061    @Inject
062    private AjaxResponseRenderer ajaxResponseRenderer;
063    
064    @Inject
065    private ComponentResources resources;
066    
067    @Inject
068    private Messages messages;
069
070    // Read value only once if showSource = true
071    private String cachedValue;
072    
073    void setupRender(MarkupWriter writer)
074    {
075     
076        cachedValue = value;
077        String elementName = resources.getElementName();
078        if (elementName == null)
079        {
080            elementName = "div";
081        }
082        
083        final String id = javaScriptSupport.allocateClientId(resources);
084        writer.element(elementName, "id", id);
085        writer.end();
086        
087        javaScriptSupport.require("t5/core/graphviz").with(cachedValue, id, showDownloadLink);
088        
089        if (showDownloadLink)
090        {
091            writer.element("a", "href", "#", "id", id + "-download", "download", id + ".svg");
092            writer.write(messages.get("download-graphviz-image"));
093            writer.end();
094        }
095        
096        if (showSource)
097        {
098            writer.element("pre", "id", id + "-source");
099            writer.write(cachedValue);
100            writer.end();
101        }
102        
103    }
104    
105}