Newer
Older
solitude / src / js / src / mdeditor / app.html
@sylow-castle sylow-castle on 30 Jul 2025 8 KB [update] add TeX
<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta charset="utf-8">
  <title>Marked in the browser</title>
  <style>
    html {
      width: auto;
    }

    div.main_pane {
      display: block;
      /*overflow: scroll;*/
      white-space: nowrap;
    }

    div.menu_pane {
      display: inline-block;
      vertical-align: top;
      position: fixed;
    }

    #editor {
      margin-top: 2em;
    }

    div.sub_pane {
      display: inline-block;
      width: 500px;
      vertical-align: top;
    }

    #content {
      display: inline-block;
      width: 210mm;
      overflow-x: visible;
    }

    #content_parent {
      max-width: 100%;
      white-space: normal;
    }

    img {
      max-width: 100%;
    }

    #content p {
      max-width: 100%;
      word-wrap: break-word;
    }

    #content pre {
      max-width: 100%;
      white-space: pre-wrap;
    }

    div.header {
      width: 480px;
      height: 20px;
      background-color: #3080ff;
    }

    div.indicator {
      position: absolute;
    }

    div.sleep {
      display: none;
    }
  </style>
  <style>
    @import url('markdown.css');
  </style>
  <style>
    @media print {

      div.menu_pane,
      div.noprint {
        display: none
      }

      #content {
        display: block
      }
    }
  </style>
</head>

<body>
  <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
  <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
  <div class="main_pane">
    <div class="menu_pane">
      <div class="header"></div>
      <div class="header indicator sleep"></div>
      <p>
      </p>
      <ul>
        <li><a href="license.md">ライセンス</a></li>
        <li><input id="update" type="button" value="更新"></li>
        <li><input id="print" type="button" value="印刷" onclick="window.print();"></li>
        <li><input id="choose_markdown" type="file"></li>
        <li><input id="newWindow" type="button" value="新しいウィンドウ"></li>
        <li>基底フォルダ<input id="currentDir" type="text" value=""></li>
        <li><input id="download" type="button" value="保存"><input id="filename" type="text" value="新しいマークダウン.txt"></li>
        <li><span class="continuous">自動更新</span><input id="continuous" type="checkbox" checked></li>
      </ul>
      <p></p>
      <p>
        <textarea id="editor" cols="40" rows="10" wrap="off"></textarea>
      </p>
    </div>
    <div class="sub_pane noprint">
    </div>
    <div class="sub_pane" id="content">
      <div id="content_parent">
        <h1 id="marked-in-the-browser">Marked in the browser</h1>
        <p>Rendered by <strong>marked</strong>.</p>
      </div>
    </div>
  </div>
  <script src="lib/marked.js"></script>
  <script src="lib/purify.js"></script>
  <script>
    default_conf = {
      "rows": 30,
      "cols": 40,
      "wrap": "off",
      "md_compiler": marked
    };

    config = {};
    function setConfig(conf) {
      config.row = conf.rows || default_conf.row;
      config.cols = conf.cols || default_conf.cols;
      config.wrap = conf.wrap || default_conf.wrap;
      config.md_compiler = conf.md_compiler || default_conf.md_compiler;
    }

    function draggableMenu() {


      function indicateDropPosition(position) {
        let indicator = document.querySelector("div.indicator")
        indicator.style.top.position.y;
        indicator.style.left.position.x;


        indicator.classList.remove("sleep");
      }

      function moveEditor(before, after) {

      }

    }

    window.onload = function main() {
      setContent('# Marked in the browser\n\nRendered by **marked**.');
      var editor = document.querySelector("#editor");
      /*
      editor.setAttribute('cols', config.cols);
      editor.setAttribute('rows', config.rows);
      editor.setAttribute('wrap', config.wrap);
      */
      LoadMainData()

      document.getElementById("choose_markdown").addEventListener("change", function () {
        var files = document.getElementById('choose_markdown').files;
        for (var i = 0; i < files.length; i++) {
          var file = files[i];
          var reader = new FileReader();
          reader.onprogress = function (evt) {
            console.log("State: " + target.readyState);
            console.log("Loaded: " + evt.loaded);
            console.log("Total: " + evt.total);
          };;
          reader.onload = function (evt) {
            console.log("State: " + evt.target.readyState);
            console.log("Result: " + evt.target.result);
            document.getElementById("editor").value = evt.target.result;
          };
          reader.onerror = function (evt) {
            console.log(evt.target.error.name);
          };
          reader.readAsText(file, "utf-8");
        }

      });


      document.querySelector('#editor').addEventListener('paste', (event) => {
        console.log(event);
        let paste = (event.clipboardData || window.clipboardData).getData('image/png');
        console.log(paste);
      });



    };

    document.querySelector("#update").addEventListener('click', function () {
      var currentContent = document.querySelector("#editor").value;
      setContent(currentContent);
    });

    document.querySelector("#download").addEventListener('click', function () {
      const currentContent = document.querySelector("#editor").value;
      const currentName = document.querySelector('#filename').value;
      download(currentName, currentContent);
    })

    const autoUpdate = function () { return document.querySelector("#continuous") };;

    document.querySelector("span.continuous").addEventListener('click', function () {
      autoUpdate().click();
    })

    autoUpdate().addEventListener('change', function () {
      console.log("changed!");
      console.log(autoUpdate().checked);
    });

    document.querySelector('#editor').addEventListener('input', function () {
      if (autoUpdate().checked) {
        document.querySelector('#update').click();
      }
    })

    function setContent(content) {
      const baseDir = document.querySelector("#currentDir").value

      const html = DOMPurify.sanitize(marked(content))
      MathJax.texReset();
      MathJax.typesetClear();
      const parent = document.querySelector('#content_parent');

      const canp = document.createElement("div");
      window.MathJax.tex = {
          inlineMath: [['%', '%'], ['$', '$'], ['\\(', '\\)']]
      };

      canp.innerHTML =  content;
      MathJax.typesetPromise([canp]).catch(function (err) {
            output.innerHTML = '';
            output.appendChild(document.createTextNode(err.message));
            console.error(err);
        });

        parent.innerHTML = compile(canp.innerHTML);
        console.log(parent.innerHTML);


      changeDir(document.querySelector('#content_parent'), baseDir)
    }

    function compile(content) {
      return DOMPurify.sanitize(marked(content))
      //return config.md_compiler(markdown);
    }

    function LoadMainData() {
      /*
      fetch(decideMainData())
        .then(function (response) {
          return response.text();
        }).then(function (responseText) {
            setContent(responseText);
        }).catch(function () {
            setContent("データの読み込みに失敗しました");
        });
        */
    };

    function decideMainData() {
      const url = (new URL(document.location)).searchParams;
      return (data = url.get("data")) ? data : "LICENSE.md";
    }

    function download(filename, content) {
      const blob = new Blob([content], { "type": "text/plain" });
      const link = document.createElement('a');

      link.href = window.URL.createObjectURL(blob);
      link.download = filename;
      link.click()
    }

    function changeDir(html, currentDir) {
      const target = html.querySelectorAll("img");
      if(target === null) {
        return html;
      }

      target.forEach(function(elem) {
        let uri = currentDir + elem.getAttribute('src');
        elem.setAttribute('src', uri);
      })

      return html;
    }

  </script>
</body>

</html>