package com.kodcu.engine; import com.kodcu.component.ViewPanel; import com.kodcu.config.*; import com.kodcu.controller.ApplicationController; import com.kodcu.other.ConverterResult; import com.kodcu.other.Current; import com.kodcu.other.IOHelper; import com.kodcu.service.DirectoryService; import com.kodcu.service.ThreadService; import javafx.application.Platform; import javafx.scene.web.WebView; import netscape.javascript.JSObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.json.JsonObject; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; /** * Created by usta on 09.04.2015. */ @Component("WebkitEngine") public class AsciidocWebkitConverter extends ViewPanel implements AsciidocConvertible { private final PreviewConfigBean previewConfigBean; private final OdfConfigBean odfConfigBean; private final DocbookConfigBean docbookConfigBean; private final HtmlConfigBean htmlConfigBean; private final AsciidocConfigMerger configMerger; private final Map<String, CompletableFuture<ConverterResult>> webWorkerTasks = new ConcurrentHashMap(); @Value("${application.index.url}") private String indexUrl; private Logger logger = LoggerFactory.getLogger(AsciidocWebkitConverter.class); private final DirectoryService directoryService; @Autowired public AsciidocWebkitConverter(ThreadService threadService, ApplicationController controller, Current current, PreviewConfigBean previewConfigBean, OdfConfigBean odfConfigBean, DocbookConfigBean docbookConfigBean, HtmlConfigBean htmlConfigBean, AsciidocConfigMerger configMerger, DirectoryService directoryService) { super(threadService, controller, current); this.previewConfigBean = previewConfigBean; this.odfConfigBean = odfConfigBean; this.docbookConfigBean = docbookConfigBean; this.htmlConfigBean = htmlConfigBean; this.configMerger = configMerger; this.directoryService = directoryService; } public String getTemplate(String templateDir) { Path path = controller.getConfigPath().resolve("slide/templates").resolve(templateDir); if (Files.notExists(path)) { logger.error("Template not found in {}", path); return ""; } String template = IOHelper.readFile(path); return template; } public JSObject getWindow() { return (JSObject) webEngine().executeScript("window"); } @Override public void runScroller(String text) { // no-op } @Override public void scrollByPosition(String text) { // no-op } @Override public void scrollByLine(String text) { // no-op } @Override public void browse() { controller.browseInDesktop(String.format(indexUrl, controller.getPort(), directoryService.interPath())); } @Override public void fillOutlines(Object doc) { threadService.runActionLater(() -> { try { getWindow().call("fillOutlines", doc); } catch (Exception e) { logger.debug("Problem occured while filling outlines", e); } }); } @Override public String applyReplacements(String asciidoc) { if (!Platform.isFxApplicationThread()) { CompletableFuture<String> completableFuture = new CompletableFuture<>(); completableFuture.runAsync(() -> { threadService.runActionLater(() -> { try { String replacements = applyReplacements(asciidoc); completableFuture.complete(replacements); } catch (Exception e) { completableFuture.completeExceptionally(e); } }); }); return completableFuture.join(); } try { return (String) getWindow().call("apply_replacements", asciidoc); } catch (Exception e) { logger.debug("Problem occured while applying replacements", e); } return asciidoc; } public String findRenderedSelection(String content) { this.setMember("context", content); return (String) webEngine().executeScript("findRenderedSelection(context)"); } protected ConverterResult convert(String functionName, String asciidoc, JsonObject config) { final CompletableFuture<ConverterResult> completableFuture = new CompletableFuture(); final String taskId = UUID.randomUUID().toString(); webWorkerTasks.put(taskId, completableFuture); final String conf = config.toString(); threadService.runActionLater(() -> { this.setMember("taskId", taskId); this.setMember("editorValue", asciidoc); this.setMember("editorOptions", conf); try { webEngine().executeScript(String.format("if ((typeof %s)!== \"undefined\"){ %s(taskId,editorValue,editorOptions) }", functionName, functionName)); } catch (Exception e) { completableFuture.completeExceptionally(e); } }); try { return completableFuture.get(60, TimeUnit.SECONDS); } catch (Exception e) { throw new RuntimeException(e); } } private JsonObject updateConfig(String asciidoc, JsonObject config) { return configMerger.updateConfig(asciidoc, config); } @Override public ConverterResult convertDocbook(String asciidoc) { return convert("convertDocbook", asciidoc, updateConfig(asciidoc, docbookConfigBean.getJSON())); } @Override public ConverterResult convertAsciidoc(String asciidoc) { return convert("convertAsciidoc", asciidoc, updateConfig(asciidoc, previewConfigBean.getJSON())); } @Override public ConverterResult convertHtml(String asciidoc) { return convert("convertHtml", asciidoc, updateConfig(asciidoc, htmlConfigBean.getJSON())); } @Override public void convertOdf(String asciidoc) { convert("convertOdf", asciidoc, updateConfig(asciidoc, odfConfigBean.getJSON())); } public Map<String, CompletableFuture<ConverterResult>> getWebWorkerTasks() { return webWorkerTasks; } public boolean isHtml(String text) { Object isHtml = this.call("isHtml", text); if (isHtml instanceof Boolean) { return (boolean) isHtml; } return false; } }