start/main.js

// Le js chargé par index.html au pnpm start
import { addElt, empty, ge } from 'src/kernel/dom'
import { figRepOrthonorm } from 'src/kernel/figures'
import { getOptsApiEditeur, getOptsApiLecteur, getOptsApiLecteurBis } from 'src/start/api'
import { addMtgElt, playerMultEltAction } from 'src/start/others'
import { getOptsJavascriptCode, getOptsJavascriptCodeId, getOptsJs, getOptsPython, getOptsPythonCode, getOptsPythonCodeId } from 'src/start/uiCommands'
import { fig1, fig2 } from './figures'

const container = ge('main')
const infos = ge('infos')
const choices = ge('testList')

function getTime () {
  const d = new Date()
  return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}.${d.getMilliseconds()}`
}

function callBackAfterReady (app) {
  console.info(getTime(), 'app is ready', app)
  // on ajoute ce comportement de resize automatique au pnpm start,
  // mais pas dans tous les cas
  if (['#playerMultElt'].includes(location.hash)) return
  function resize () {
    const width = document.documentElement.clientWidth
    const height = document.documentElement.clientHeight
    app.resize(width, height)
  }
  if (app.addQueue) {
    app.addQueue(() => {
      resize()
    })
    window.addEventListener('resize', () => app.addQueue(function () {
      resize()
    }))
  }
}

// nos options par défaut, qui seront surchargées suivant les cas
/** @type {MtgOptions} */
const mtgOptions = {
  level: 3,
  translatable: true,
  dys: false,
  newFig: true,
  open: true,
  options: true,
  stylePointCroix: true,
  save: true, // pour que l'outil permettant d'enregistrer une figure soit présent
  zoomOnWheel: true,
  useLens: true,
  callBackAfterReady
}

// les exemples proposés
const samples = {
  player: {
    desc: 'figure de test avec le player',
    opts: {
      fig: fig1,
      isEditable: false
    }
  },
  fig1: {
    desc: 'figure de test 1 avec l’éditeur',
    opts: { fig: fig1 }
  },
  fig1PlayerElt: {
    desc: 'figure de test 1 avec <mathgraph-player>',
    action: () => addMtgElt(container, { fig: fig1 })
  },
  fig1EditorElt: {
    desc: 'figure de test 1 avec <mathgraph-editor>',
    action: () => addMtgElt(container, { fig: fig1 }, true)
  },
  fig2: {
    desc: 'figure de test 2 avec l’éditeur',
    opts: { fig: fig2 }
  },
  editeur: {
    desc: 'Éditeur sans figure avec un repère',
    opts: {
      fig: {
        type: 'orthonormal',
        datarep: {
          quadhor: false,
          quadver: false,
          grid: true,
          withvect: false,
          grad: 'simple'
        },
        unity: 'rad'
      }
    }
  },
  apiEditeur: {
    desc: 'test api sur une figure vide de l’éditeur',
    action: (mtgOptions) => Object.assign(mtgOptions, getOptsApiEditeur())
  },

  apiLecteur: {
    desc: 'test api sur une figure du player',
    action: (mtgOptions) => Object.assign(mtgOptions, getOptsApiLecteur())
  },

  apiLecteurBis: {
    desc: 'test api sur une figure vide du player avec objets retournés',
    action: (mtgOptions) => Object.assign(mtgOptions, getOptsApiLecteurBis())
  },

  python: {
    desc: 'test de l’éditeur de commande python',
    action: (mtgOptions) => Object.assign(mtgOptions, getOptsPython())
  },
  pythonCode: {
    desc: 'test du chargement via du code python',
    action: (mtgOptions) => Object.assign(mtgOptions, getOptsPythonCode())
  },
  pythonCodeId: {
    desc: 'test du chargement via du code python par id',
    action: (mtgOptions) => Object.assign(mtgOptions, getOptsPythonCodeId())
  },
  pythonCodeIdElt: {
    desc: 'test du chargement via <mathgraph-player code-python-id="">',
    action: async () => {
      const { pythonCodeId } = getOptsPythonCodeId()
      await addMtgElt(container, { 'python-code-id': pythonCodeId, fig: figRepOrthonorm })
    }
  },
  hiddenPythonCodeIdElt: {
    desc: 'test du chargement via <mathgraph-player code-python-id=""> sans l’éditeur python',
    action: async () => {
      const { pythonCodeId } = getOptsPythonCodeId()
      await addMtgElt(container, { 'python-code-id': pythonCodeId, fig: figRepOrthonorm, 'hide-commands': true })
    }
  },
  // avec le suffixe Elt mtgLoad se lance pas tout seul
  playerMultElt: {
    desc: 'test avec plusieurs figures (player) chargées différemment (mtgLoad, tag mathgraph player avec fig et tag avec python-code-id)',
    action: playerMultEltAction
  },
  javascript: {
    desc: 'test de l’éditeur de commande javascript',
    action: (mtgOptions) => Object.assign(mtgOptions, getOptsJs())
  },
  javascriptCode: {
    desc: 'test du chargement via du code javascript',
    action: (mtgOptions) => Object.assign(mtgOptions, getOptsJavascriptCode())
  },
  javascriptCodeId: {
    desc: 'test du chargement via du code javascript par id',
    action: (mtgOptions) => Object.assign(mtgOptions, getOptsJavascriptCodeId())
  },
  javascriptCodeIdElt: {
    desc: 'test du chargement via <mathgraph-player code-javascript-id="">',
    action: async () => {
      const { javascriptCodeId } = getOptsJavascriptCodeId()
      await addMtgElt(container, { 'javascript-code-id': javascriptCodeId, fig: figRepOrthonorm })
    }
  },
  hiddenJavascriptCodeIdElt: {
    desc: 'test du chargement via <mathgraph-player code-javascript-id=""> sans l’éditeur javascript',
    action: async () => {
      const { javascriptCodeId } = getOptsJavascriptCodeId()
      await addMtgElt(container, { 'javascript-code-id': javascriptCodeId, fig: figRepOrthonorm, 'hide-commands': true })
    }
  }
}

async function init () {
  const module = await import('src/mtgLoad.js')
  // faut le mettre en global pour que les custom elts l'utilise (au lieu d'en charger un en dev)
  window.mtgLoad = module.default

  // on ajoute les li dans le html
  for (const [name, { desc }] of Object.entries(samples)) {
    const li = addElt(choices, 'li')
    const a = addElt(li, 'a', desc)
    a.setAttribute('href', `#${name}`)
  }
}

async function reload () {
  try {
    // le hash sans son préfixe #
    const hash = window.location.hash.substring(1)
    empty(container)
    // faut aussi virer d'éventuels scripts python mis dans le dom
    for (const script of document.querySelectorAll('script[type="text/mtgPython"]')) {
      script.parentNode.removeChild(script)
    }
    // idem pour les scripts js
    for (const script of document.querySelectorAll('script[type="text/mtgJavascript"]')) {
      script.parentNode.removeChild(script)
    }

    console.debug('reload avec', hash || ' la liste des exemple')
    let showInfos = true
    let isLoadedWithElement = false

    // on permet de charger différents cas suivant le hash passé à la page
    if (samples[hash]) {
      showInfos = false
      isLoadedWithElement = hash.endsWith('Elt')
      const { desc, opts, action } = samples[hash]
      console.info(desc)
      if (opts) Object.assign(mtgOptions, opts)
      if (action) {
        const result = action(mtgOptions)
        if (result instanceof Promise) await result
      }
    } else {
      // les cas génériques où on passe une figure base64 dans le hash
      const chunks = /^(player|fixed|editor|playerElt|editorElt)(.+)$/.exec(hash)
      if (chunks) {
        showInfos = false
        const [, type, fig] = chunks
        if (type.endsWith('Elt')) {
          // via un custom tag
          await addMtgElt(container, { fig }, type === 'editorElt')
          isLoadedWithElement = true
        } else {
          console.info(`figure de test avec ${type} et la figure base64 passée en argument`)
          // on charge la figure base64 passée en hash avec le player
          mtgOptions.fig = fig
          mtgOptions.isEditable = type === 'editor'
          if (type === 'fixed') mtgOptions.isInteractive = false
        }
      }
    }

    // si on nous file qqchose à afficher on le fait
    if (showInfos) {
      // on affiche les choix
      infos.style.display = 'block'
    } else {
      infos.style.display = 'none'
      // faut lancer mtgLoad, sauf si on a mis un custom elt
      if (!isLoadedWithElement) {
        console.info('on lance mtgLoad avec les options', mtgOptions)
        const app = await window.mtgLoad(container, {}, mtgOptions)
        console.info(getTime(), 'mtgLoad a chargé l’appli (pas forcément ready)', app)
      }
    }
  } catch (error) {
    console.error(error)
  }
} // reload

init().then(() => {
  window.addEventListener('hashchange', reload)
  // au clic sur page précédente, les liens devenaient inactifs (le clic sur un lien ne modifiait pas le hash)
  // on cherche pas trop à comprendre, on recharge tout
  window.addEventListener('popstate', () => window.location.reload())
  // premier lancement
  return reload()
}).catch(error => console.error(error))