Newer
Older
solitude / src / js / src / main / app.js
@sylow-castle sylow-castle on 10 Jul 7 KB [update]
import { Que } from "../js/Que.js";
import { graftSolitude } from "..//js/solitude.js";
import { SyslogStmt } from "../js/SyslogStmt.js";
import { LogReceiverReadyMessage } from "./shared/LogReceiverReadyMessage.js";
import { webconfig } from "./WebConfig.js";

window.addEventListener('load', main(document));

function main(document) {
  const kernelLogger = window.kernelLogger
  kernelLogger.info("main started");
  graftSolitude(window);
  webconfig(window);
  const mysolitude = window.solitude;
  mysolitude.apps = {};
  Object.assign(mysolitude.apps, window.tmp.solitudeapps);

  //アプリケーション毎に初期化操作
  initializeSolitudeApps(mysolitude.apps)

  Que("li.tab").list().forEach(function (val, index, _list) {
    val.addEventListener("click", function () {
      selectTab(index);
    });
  })

  const leftMenu = Que("#left-menu").get();
  const menuToggle = Que("#menu-toggle").get();
  menuToggle.addEventListener("click", function () {
    leftMenu.classList.remove("initial")
    toggleMenuItem(leftMenu);
    Que("#left-menu li span").list().forEach(function (val) {
      toggleMenuItem(val);
    })
    toggleMenuItem(Que("#main").get());

  });


  // app.js の main 関数内など
  mysolitude.message.addListener(LogReceiverReadyMessage.filter((message) => {
    // kernelLoggerにログを引き渡すレシーバーを設定
    kernelLogger.takeover({
      receive: receive,
    });

    // 溜まっていたログをフラッシュする
    kernelLogger.debug("flush !");
    kernelLogger.flush();

    function receive(msg) {
      mysolitude.message.fire({
        type: "log",
        message: msg
      })
    }
  }));



  const b = new SyslogStmt();
  kernelLogger.log(b.fac(20).gen("SyslogStmt test2").str);

  // 以下、宣言
  function toggleMenuItem(element) {
    if (element.classList.contains("expanded")) {
      element.classList.add("shrinked");
      element.classList.remove("expanded");
    } else {
      element.classList.add("expanded");
      element.classList.remove("shrinked");
    }
  }

  function selectTab(index) {
    let tab, content;
    Que("#main-pane li.tab").list().forEach(function (val) {
      val.classList.remove("selected");
      if (val.dataset.soloAppId == index) {
        tab = val;
      }
    });

    Que("#main-pane div.main-article").list().forEach(function (val) {
      val.classList.remove("selected");
      if (val.dataset.soloAppId == index) {
        content = val;
      }
    });

    tab.classList.add("selected");
    content.classList.add("selected");
  }

  function initializeSolitudeApps(apps) {
    const appsProto = {
      useMenu: true,
      useTab: true,
      autorun: false,
    };

    const appFuncs = [IframeApp, StaticPageApp, BatchApp];
    appFuncs.forEach(appFunc => {
      appFunc.prototype = appsProto;
    });

    let app;
    let appInstanceID = 0;
    for (const [name, conf] of Object.entries(apps)) {
      const appType = conf.type || "undef";
      switch (appType) {
        case "main":
        case "undef":
          app = null;
          //do nothing                            
          break;
        case "staticpage":
          app = new StaticPageApp(name, conf);
          break;
        case "iframe":
          app = new IframeApp(name, conf);
          break;
        case "batch":
          app = new BatchApp(name, conf);
          break;
        default:
          //something wrong;
          break;
      }
      if (app) {
        app.instanceID = ++appInstanceID;
        app.load();
        kernelLogger.info("loaded ".concat(name, ", instanceID ", app.instanceID));
      }

    }


    //巻き上げを期待しているためclass構文ではない。
    function IframeApp(name, conf) {
      this.name = name;
      this.conf = conf;
      this.load = loadApp;
      this.template = "#app-type-iframe";
      this.callback = iframeCallback;
    }

    function StaticPageApp(name, conf) {
      this.name = name;
      this.conf = conf;
      this.load = loadApp;
      this.template = "#app-type-staticpage";
      this.callback = staticpageCallback;
    }

    function BatchApp(name, conf) {
      this.name = name;
      this.conf = conf;
      this.load = loadBatchApp;
      this.template = "#app-type-batch";
      this.callback = batchCallback;
    }

    function loadApp() {
      addNewMenu(this.name);
      const mount = Que("#left-menu ol");
      const app = this;
      mount.que("li.init").get().addEventListener("click", function () {

        if (isInitialized(app.instanceID)) {
          return;
        }

        addNewTab(app);
        addNewContent(app);
        kernelLogger.info(app.name + " is initialized");
      });
      mount.que("li.init").get().classList.remove("init");
    }

    function isInitialized(appInstanceID) {
      //アプリのタブが出ているかでロード済みかを判断
      let result = false;
      Que("#main-tabs li").list().forEach(elem => {
        if (appInstanceID == elem.dataset.soloAppId) {
          result = true;
        }
      });
      return result;

    }

    function loadBatchApp() {
      addNewContent(this);
    }

    function addNewMenu(name) {
      const mount = Que("#left-menu ol").get();
      let menu = Que("#app-menu").get();
      menu = menu.content.cloneNode(true);

      const span = Que("span", menu).get();
      // template では初期状態はexpanded
      if (Que("#left-menu.shrinked").list().length > 0) {
        const cls = span.classList;
        cls.remove("expanded");
        cls.add("shrinked");
      }
      span.textContent = name;
      mount.appendChild(menu);
    }

    function addNewTab(app) {
      const mount = Que("#main-tabs").get();
      let tab = Que("#app-tab").get()
      tab = tab.content.cloneNode(true);
      const li = Que("li", tab).get();
      li.textContent = app.name;
      li.dataset.soloAppId = app.instanceID;
      const index = app.instanceID;
      mount.appendChild(tab);

      li.addEventListener("click", () => {
        selectTab(index);
      });
    }

    function addNewContent(app) {
      const appNode = (Que(app.template).get()).content.cloneNode(true);
      const base = Que("div.main-article", appNode);
      base.get().classList.remove("undefined");
      base.get().dataset.soloAppId = app.instanceID;
      base.que("div.app-container").get().classList.add(app.name);
      app.callback(app, base);

      const mount = Que("#app-pane").get();
      mount.appendChild(base.get());

    }

    function iframeCallback(app, base) {
      const iframe = Que("div.app-container > iframe", base).get();
      iframe.setAttribute("id", app.name);
      iframe.setAttribute("title", app.name);
      iframe.setAttribute("src", app.conf.src);
    }

    async function staticpageCallback(app, base) {
      const text = await mysolitude.io.fs.read(app.conf.src);
      const parser = new DOMParser();
      const doc = parser.parseFromString(text, "text/html");
      const content = Que("div.app-body", doc).get().cloneNode(true);
      Que("div.app-container", base).get().appendChild(content);

      //文書内のJavascriptコードを実行する。簡単な実装。
      //これだとon.loadイベントとかがキックされなくなってしまう気がする。
      const removes = [];
      Que("script", content).list().forEach(element => {
        const script = document.createElement("script")
        script.innerHTML = element.innerHTML;
        for (const attr of element.attributes) {
          script.setAttribute(attr.name, attr.value);
        }
        element.before(script)
        removes.push(element);
      });

      for (const script of removes) {
        script.remove();
      }
    }

    function batchCallback(app, base) {
      const content = document.createElement("script")
      content.setAttribute("src", app.conf.src);
      Que("div.app-container", base).get().appendChild(content);
    }
  }
}