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 lack of options.
032 * 
033 * @tapestrydoc
034 */
035public class Graphviz
036{
037    
038    /**
039     * A Graphviz graph described in its DOT language.
040     */
041    @Parameter(required = true, allowNull = false)
042    @Property
043    private String value;
044    
045    /**
046     * Defines whether a link to download the graph as an SVG file should be provided.
047     */
048    @Parameter(defaultPrefix = BindingConstants.LITERAL, value = "false")
049    private boolean showDownloadLink;
050
051    /**
052     * Defines whether a the Graphviz source should be shown.
053     */
054    @Parameter(defaultPrefix = BindingConstants.LITERAL, value = "false")
055    private boolean showSource;
056
057    @Environmental
058    private JavaScriptSupport javaScriptSupport;
059    
060    @Inject
061    private AjaxResponseRenderer ajaxResponseRenderer;
062    
063    @Inject
064    private ComponentResources resources;
065    
066    @Inject
067    private Messages messages;
068
069    // Read value only once if showSource = true
070    private String cachedValue;
071    
072    void setupRender(MarkupWriter writer)
073    {
074     
075        cachedValue = value;
076        String elementName = resources.getElementName();
077        if (elementName == null)
078        {
079            elementName = "div";
080        }
081        
082        final String id = javaScriptSupport.allocateClientId(resources);
083        writer.element(elementName, "id", id);
084        writer.end();
085        
086        javaScriptSupport.require("t5/core/graphviz").with(cachedValue, id, showDownloadLink);
087        
088        if (showDownloadLink)
089        {
090            writer.element("a", "href", "#", "id", id + "-download", "download", id + ".svg");
091            writer.write(messages.get("download-graphviz-image"));
092            writer.end();
093        }
094        
095        if (showSource)
096        {
097            writer.element("pre", "id", id + "-source");
098            writer.write(cachedValue);
099            writer.end();
100        }
101        
102    }
103    
104}