Refactored tools services endpoints system and fixed json formatter. #91
@@ -15,6 +15,7 @@
 | 
				
			|||||||
    <jackson.version>2.14.1</jackson.version>
 | 
					    <jackson.version>2.14.1</jackson.version>
 | 
				
			||||||
    <slf4j.version>2.0.6</slf4j.version>
 | 
					    <slf4j.version>2.0.6</slf4j.version>
 | 
				
			||||||
    <log4j.version>2.19.0</log4j.version>
 | 
					    <log4j.version>2.19.0</log4j.version>
 | 
				
			||||||
 | 
					    <gson.version>2.10.1</gson.version>
 | 
				
			||||||
  </properties>
 | 
					  </properties>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <build>
 | 
					  <build>
 | 
				
			||||||
@@ -68,6 +69,11 @@
 | 
				
			|||||||
    </dependency>
 | 
					    </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!--    JSON    -->
 | 
					    <!--    JSON    -->
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>com.google.code.gson</groupId>
 | 
				
			||||||
 | 
					      <artifactId>gson</artifactId>
 | 
				
			||||||
 | 
					      <version>${gson.version}</version>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
    <dependency>
 | 
					    <dependency>
 | 
				
			||||||
      <groupId>com.fasterxml.jackson.core</groupId>
 | 
					      <groupId>com.fasterxml.jackson.core</groupId>
 | 
				
			||||||
      <artifactId>jackson-core</artifactId>
 | 
					      <artifactId>jackson-core</artifactId>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
package com.r11.tools.controller;
 | 
					package com.r11.tools.controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.Gson;
 | 
				
			||||||
 | 
					import com.google.gson.GsonBuilder;
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
import com.r11.tools.controller.internal.GlobalControllerManifest;
 | 
					import com.r11.tools.controller.internal.GlobalControllerManifest;
 | 
				
			||||||
import com.r11.tools.controller.internal.HandlerType;
 | 
					import com.r11.tools.controller.internal.HandlerType;
 | 
				
			||||||
import com.r11.tools.controller.internal.RestController;
 | 
					import com.r11.tools.controller.internal.RestController;
 | 
				
			||||||
@@ -7,11 +10,46 @@ import com.r11.tools.controller.internal.ScopedControllerManifest;
 | 
				
			|||||||
import spark.Request;
 | 
					import spark.Request;
 | 
				
			||||||
import spark.Response;
 | 
					import spark.Response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@GlobalControllerManifest
 | 
					@GlobalControllerManifest(path = "/json")
 | 
				
			||||||
public class JsonController implements RestController {
 | 
					public class JsonController implements RestController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @ScopedControllerManifest(method = HandlerType.GET, path = "/json")
 | 
					  private final Gson prettyGson = new GsonBuilder()
 | 
				
			||||||
 | 
					      .disableHtmlEscaping()
 | 
				
			||||||
 | 
					      .setPrettyPrinting()
 | 
				
			||||||
 | 
					      .create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private final Gson gson = new GsonBuilder()
 | 
				
			||||||
 | 
					      .disableHtmlEscaping()
 | 
				
			||||||
 | 
					      .create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @ScopedControllerManifest(method = HandlerType.POST, path = "/formatting")
 | 
				
			||||||
  public void formatting(Request request, Response response) {
 | 
					  public void formatting(Request request, Response response) {
 | 
				
			||||||
    response.body("Hello World!");
 | 
					    try {
 | 
				
			||||||
 | 
					      JsonObject jsonObject = this.gson.fromJson(request.body(), JsonObject.class);
 | 
				
			||||||
 | 
					      response.status(200);
 | 
				
			||||||
 | 
					      response.body(this.prettyGson.toJson(jsonObject));
 | 
				
			||||||
 | 
					      System.out.printf(response.body());
 | 
				
			||||||
 | 
					    } catch (Exception e) {
 | 
				
			||||||
 | 
					      response.status(500);
 | 
				
			||||||
 | 
					      Throwable cause = e.getCause();
 | 
				
			||||||
 | 
					      if (cause == null) {
 | 
				
			||||||
 | 
					        response.body(e.getMessage());
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        response.body(cause.getMessage());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      System.out.printf(response.body());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @ScopedControllerManifest(method = HandlerType.POST, path = "/minimize")
 | 
				
			||||||
 | 
					  public void minimize(Request request, Response response) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      JsonObject jsonObject = this.prettyGson.fromJson(request.body(), JsonObject.class);
 | 
				
			||||||
 | 
					      response.status(200);
 | 
				
			||||||
 | 
					      response.body(this.gson.toJson(jsonObject));
 | 
				
			||||||
 | 
					    } catch (Exception e) {
 | 
				
			||||||
 | 
					      response.status(500);
 | 
				
			||||||
 | 
					      response.body(e.getMessage());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
package com.r11.tools.controller.internal;
 | 
					package com.r11.tools.controller.internal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.r11.tools.controller.internal.path.PathBuilder;
 | 
				
			||||||
import java.lang.reflect.Method;
 | 
					import java.lang.reflect.Method;
 | 
				
			||||||
import java.util.HashSet;
 | 
					import java.util.HashSet;
 | 
				
			||||||
import java.util.Set;
 | 
					import java.util.Set;
 | 
				
			||||||
@@ -33,7 +34,11 @@ public class RestControllerRegistry {
 | 
				
			|||||||
        (method.isAnnotationPresent(ScopedControllerManifest.class))
 | 
					        (method.isAnnotationPresent(ScopedControllerManifest.class))
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
      HandlerType handlerType = method.getAnnotation(ScopedControllerManifest.class).method();
 | 
					      HandlerType handlerType = method.getAnnotation(ScopedControllerManifest.class).method();
 | 
				
			||||||
      String path = method.getAnnotation(ScopedControllerManifest.class).path();
 | 
					
 | 
				
			||||||
 | 
					      String path = PathBuilder.resolvePathOf(
 | 
				
			||||||
 | 
					          parent.getAnnotation(GlobalControllerManifest.class).path(),
 | 
				
			||||||
 | 
					          method.getAnnotation(ScopedControllerManifest.class).path()
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      switch (handlerType) {
 | 
					      switch (handlerType) {
 | 
				
			||||||
        case GET:
 | 
					        case GET:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					package com.r11.tools.controller.internal.path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public final class PathBuilder {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private static final String PATH_SEPARATOR = "/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private PathBuilder() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public static String resolvePathOf(String globalPath, String scopedPath) {
 | 
				
			||||||
 | 
					    String resolvedPath =
 | 
				
			||||||
 | 
					        PathBuilder.removeTrailingPathSeparator(globalPath) +
 | 
				
			||||||
 | 
					        PathBuilder.removeTrailingPathSeparator(scopedPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (resolvedPath.endsWith(PATH_SEPARATOR)) {
 | 
				
			||||||
 | 
					      resolvedPath = resolvedPath.substring(0, resolvedPath.length() - 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return PATH_SEPARATOR + resolvedPath;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private static String removeTrailingPathSeparator(String path) {
 | 
				
			||||||
 | 
					    if (path.endsWith(PATH_SEPARATOR)) {
 | 
				
			||||||
 | 
					      return path.substring(0, path.length() - 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return path;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,21 +1,33 @@
 | 
				
			|||||||
function formatAndValidateJson(errorElement) {
 | 
					function formatAndValidateJson(errorElement) {
 | 
				
			||||||
  const input = document.querySelector('#jsonBlock');
 | 
					  const input = document.querySelector('#jsonBlock');
 | 
				
			||||||
  const processInfo = document.getElementById(errorElement);
 | 
					  const processInfo = document.getElementById(errorElement);
 | 
				
			||||||
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
  const start = new Date();
 | 
					  const start = new Date();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const obj = JSON.parse(input.textContent);
 | 
					  const address = window.location.protocol + "//" + window.location.hostname + ":" + 8081 + "/json/formatting"
 | 
				
			||||||
    input.innerHTML = JSON.stringify(obj, null, 2);
 | 
					
 | 
				
			||||||
 | 
					  fetch(address, {
 | 
				
			||||||
 | 
					    method: 'POST',
 | 
				
			||||||
 | 
					    body: input.textContent
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  .then(async (response) => {
 | 
				
			||||||
 | 
					    if (!response.ok) {
 | 
				
			||||||
 | 
					      throw Error(await response.text());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return response.text();
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  .then((data) => {
 | 
				
			||||||
 | 
					    input.innerText = data;
 | 
				
			||||||
    processInfo.innerText = "";
 | 
					    processInfo.innerText = "";
 | 
				
			||||||
    hljs.highlightElement(input);
 | 
					    hljs.highlightElement(input);
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  .catch((error) => {
 | 
				
			||||||
 | 
					    processInfo.innerHTML = "<b style='color: red'>" + error + "</b>";
 | 
				
			||||||
 | 
					    console.error('Error:', error);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const end = new Date();
 | 
					  const end = new Date();
 | 
				
			||||||
  processInfo.innerHTML = "<b style='color: black'>Validation and formatting time:</b> <span style='color: green'>" + (end.getMilliseconds() - start.getMilliseconds()) + "ms</span>";
 | 
					  processInfo.innerHTML = "<b style='color: black'>Validation and formatting time:</b> <span style='color: green'>" + (end.getMilliseconds() - start.getMilliseconds()) + "ms</span>";
 | 
				
			||||||
  } catch (error) {
 | 
					 | 
				
			||||||
    processInfo.innerHTML = "<b style='color: red'>" + error + "</b>";
 | 
					 | 
				
			||||||
    console.error("Error: ", error)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function minimizeJson(errorElement) {
 | 
					function minimizeJson(errorElement) {
 | 
				
			||||||
@@ -31,7 +43,8 @@ function minimizeJson(errorElement) {
 | 
				
			|||||||
    hljs.highlightElement(input);
 | 
					    hljs.highlightElement(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const end = new Date();
 | 
					    const end = new Date();
 | 
				
			||||||
    processInfo.innerHTML = "<b style='color: black'>Validation and formatting time:</b> <span style='color: green'>" + (end.getMilliseconds() - start.getMilliseconds()) + "ms</span>";
 | 
					    processInfo.innerHTML = "<b style='color: black'>Validation and formatting time:</b> <span style='color: green'>"
 | 
				
			||||||
 | 
					        + (end.getMilliseconds() - start.getMilliseconds()) + "ms</span>";
 | 
				
			||||||
  } catch (error) {
 | 
					  } catch (error) {
 | 
				
			||||||
    processInfo.innerHTML = "<b style='color: red'>" + error + "</b>";
 | 
					    processInfo.innerHTML = "<b style='color: red'>" + error + "</b>";
 | 
				
			||||||
    console.error("Error: ", error)
 | 
					    console.error("Error: ", error)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,6 +52,167 @@
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <script>
 | 
					    <script>
 | 
				
			||||||
 | 
					      const mergeHTMLPlugin = (function () {
 | 
				
			||||||
 | 
					        'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var originalStream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * @param {string} value
 | 
				
			||||||
 | 
					         * @returns {string}
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        function escapeHTML(value) {
 | 
				
			||||||
 | 
					          return value
 | 
				
			||||||
 | 
					          .replace(/&/g, '&')
 | 
				
			||||||
 | 
					          .replace(/</g, '<')
 | 
				
			||||||
 | 
					          .replace(/>/g, '>')
 | 
				
			||||||
 | 
					          .replace(/"/g, '"')
 | 
				
			||||||
 | 
					          .replace(/'/g, ''');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* plugin itself */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /** @type {HLJSPlugin} */
 | 
				
			||||||
 | 
					        const mergeHTMLPlugin = {
 | 
				
			||||||
 | 
					          // preserve the original HTML token stream
 | 
				
			||||||
 | 
					          "before:highlightElement": ({el}) => {
 | 
				
			||||||
 | 
					            originalStream = nodeStream(el);
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          // merge it afterwards with the highlighted token stream
 | 
				
			||||||
 | 
					          "after:highlightElement": ({el, result, text}) => {
 | 
				
			||||||
 | 
					            if (!originalStream.length) {
 | 
				
			||||||
 | 
					              return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const resultNode = document.createElement('div');
 | 
				
			||||||
 | 
					            resultNode.innerHTML = result.value;
 | 
				
			||||||
 | 
					            result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
 | 
				
			||||||
 | 
					            el.innerHTML = result.value;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * @param {Node} node
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        function tag(node) {
 | 
				
			||||||
 | 
					          return node.nodeName.toLowerCase();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * @param {Node} node
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        function nodeStream(node) {
 | 
				
			||||||
 | 
					          /** @type Event[] */
 | 
				
			||||||
 | 
					          const result = [];
 | 
				
			||||||
 | 
					          (function _nodeStream(node, offset) {
 | 
				
			||||||
 | 
					            for (let child = node.firstChild; child; child = child.nextSibling) {
 | 
				
			||||||
 | 
					              if (child.nodeType === 3) {
 | 
				
			||||||
 | 
					                offset += child.nodeValue.length;
 | 
				
			||||||
 | 
					              } else if (child.nodeType === 1) {
 | 
				
			||||||
 | 
					                result.push({
 | 
				
			||||||
 | 
					                  event: 'start',
 | 
				
			||||||
 | 
					                  offset: offset,
 | 
				
			||||||
 | 
					                  node: child
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                offset = _nodeStream(child, offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!tag(child).match(/br|hr|img|input/)) {
 | 
				
			||||||
 | 
					                  result.push({
 | 
				
			||||||
 | 
					                    event: 'stop',
 | 
				
			||||||
 | 
					                    offset: offset,
 | 
				
			||||||
 | 
					                    node: child
 | 
				
			||||||
 | 
					                  });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return offset;
 | 
				
			||||||
 | 
					          })(node, 0);
 | 
				
			||||||
 | 
					          return result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * @param {any} original - the original stream
 | 
				
			||||||
 | 
					         * @param {any} highlighted - stream of the highlighted source
 | 
				
			||||||
 | 
					         * @param {string} value - the original source itself
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        function mergeStreams(original, highlighted, value) {
 | 
				
			||||||
 | 
					          let processed = 0;
 | 
				
			||||||
 | 
					          let result = '';
 | 
				
			||||||
 | 
					          const nodeStack = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          function selectStream() {
 | 
				
			||||||
 | 
					            if (!original.length || !highlighted.length) {
 | 
				
			||||||
 | 
					              return original.length ? original : highlighted;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (original[0].offset !== highlighted[0].offset) {
 | 
				
			||||||
 | 
					              return (original[0].offset < highlighted[0].offset) ? original : highlighted;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return highlighted[0].event === 'start' ? original : highlighted;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          /**
 | 
				
			||||||
 | 
					           * @param {Node} node
 | 
				
			||||||
 | 
					           */
 | 
				
			||||||
 | 
					          function open(node) {
 | 
				
			||||||
 | 
					            /** @param {Attr} attr */
 | 
				
			||||||
 | 
					            function attributeString(attr) {
 | 
				
			||||||
 | 
					              return ' ' + attr.nodeName + '="' + escapeHTML(attr.value) + '"';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // @ts-ignore
 | 
				
			||||||
 | 
					            result += '<' + tag(node) + [].map.call(node.attributes, attributeString).join('')
 | 
				
			||||||
 | 
					                + '>';
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          /**
 | 
				
			||||||
 | 
					           * @param {Node} node
 | 
				
			||||||
 | 
					           */
 | 
				
			||||||
 | 
					          function close(node) {
 | 
				
			||||||
 | 
					            result += '</' + tag(node) + '>';
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          /**
 | 
				
			||||||
 | 
					           * @param {Event} event
 | 
				
			||||||
 | 
					           */
 | 
				
			||||||
 | 
					          function render(event) {
 | 
				
			||||||
 | 
					            (event.event === 'start' ? open : close)(event.node);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          while (original.length || highlighted.length) {
 | 
				
			||||||
 | 
					            let stream = selectStream();
 | 
				
			||||||
 | 
					            result += escapeHTML(value.substring(processed, stream[0].offset));
 | 
				
			||||||
 | 
					            processed = stream[0].offset;
 | 
				
			||||||
 | 
					            if (stream === original) {
 | 
				
			||||||
 | 
					              /*
 | 
				
			||||||
 | 
					              On any opening or closing tag of the original markup we first close
 | 
				
			||||||
 | 
					              the entire highlighted node stack, then render the original tag along
 | 
				
			||||||
 | 
					              with all the following original tags at the same offset and then
 | 
				
			||||||
 | 
					              reopen all the tags on the highlighted stack.
 | 
				
			||||||
 | 
					              */
 | 
				
			||||||
 | 
					              nodeStack.reverse().forEach(close);
 | 
				
			||||||
 | 
					              do {
 | 
				
			||||||
 | 
					                render(stream.splice(0, 1)[0]);
 | 
				
			||||||
 | 
					                stream = selectStream();
 | 
				
			||||||
 | 
					              } while (stream === original && stream.length && stream[0].offset === processed);
 | 
				
			||||||
 | 
					              nodeStack.reverse().forEach(open);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              if (stream[0].event === 'start') {
 | 
				
			||||||
 | 
					                nodeStack.push(stream[0].node);
 | 
				
			||||||
 | 
					              } else {
 | 
				
			||||||
 | 
					                nodeStack.pop();
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              render(stream.splice(0, 1)[0]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return result + escapeHTML(value.substr(processed));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return mergeHTMLPlugin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      hljs.addPlugin(mergeHTMLPlugin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const editorEle = document.getElementById('jsonBlock');
 | 
					      const editorEle = document.getElementById('jsonBlock');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user