dialogs/ChoixOutilsDlg.js

/*
 * MathGraph32 Javascript : Software for animating online dynamic mathematics figures
 * https://www.mathgraph32.org/
 * @Author Yves Biton (yves.biton@sesamath.net)
 * @License: GNU AGPLv3 https://www.gnu.org/licenses/agpl-3.0.html
 */
import { ce, getAbsolutePath, getStr } from '../kernel/kernel'
import MtgDlg from './MtgDlg'
import CMathGraphDoc from '../objets/CMathGraphDoc'
import $ from 'jquery'
import 'jstree'
import 'jstree/dist/themes/default/style.min.css'
// attention, jstree fait un require jquery et ajoute des choses dessus sans le renvoyer
// => il faut un resolve.alias.jquery dans webpack.config.cjs pour imposer le module à prendre,
//    histoire que tout le monde récupère la même instance, car il pourrait y avoir plusieurs
//    jquery dans node_modules
// => $.jstree.plugins.types.get_node veut du jQuery en global, on pourrait le mettre via un
//    new webpack.ProvidePlugin({'jQuery': 'jquery'})
//    dans la conf webpack, mais ça ajouterait jquery à tous les builds, on le fait ici
window.jQuery = $

export default ChoixOutilsDlg

/**
 * Boîte de dialogue de choix des outils disponibles pour la figure en cours
 * @constructor
 * @param {MtgApp} app L'application propriétaire
 * @param {CMathGraphDoc} doc Un document dans lequel les choix d'outils seront enregistrés après validation de la boîte de dialogue
 * @param niv Le niveau de filtarge des outils proposés
 * @param {null|CMathGraphDoc} docNiv Un éventuel doc contenant les infos pour les outils à sléectionner ou non
 * @param {boolean} persDispo true si on propose de choisir les outils sélections pour le prochaine démarrage
 */
function ChoixOutilsDlg (app, doc, niv, docNiv, persDispo) {
  let tr, div, label, radio, i, cb
  MtgDlg.call(this, app, 'OutilAddDlg')
  this.doc = doc // Servira lors de la validation
  // docNiv n'est passé en paramètre que si on a choisi d'utiliser un fichier mgj pour sélectionner les outils
  // sinon il est null
  this.docNiv = docNiv || doc
  this.niv = niv
  this.persDispo = persDispo
  const tabPrincipal = ce('table')
  this.appendChild(tabPrincipal)
  /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // En bas, un label et deux boutons radio pour savoir si les outils sohés sont les outils permis ou interdits  //
  /// //////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Même pour la version electron, on ne propose pas de choisir les outils sélectionnés pour le prochain démarrage
  // du logiciel dans le cas où, dans la boîte de dialogue d'options, on a coché Utiliser ce niveau pour le prochain démarrage
  if ((app.electron || app.pwa) && persDispo) {
    tr = ce('tr')
    tabPrincipal.appendChild(tr)
    div = ce('div')
    tr.appendChild(div)
    cb = ce('input', {
      type: 'checkbox',
      id: 'cb'
    })
    div.appendChild(cb)
    label = ce('label', {
      for: 'cb'
    })
    $(label).html(getStr('ToolsDem'))
    div.appendChild(label)
  }
  tr = ce('tr')
  tabPrincipal.appendChild(tr)

  label = ce('label')
  $(label).html(getStr('ChoixOutDlg1'))
  tr.appendChild(label)
  tr = ce('tr')
  tabPrincipal.appendChild(tr)
  div = ce('div')
  tr.appendChild(div)
  radio = ce('input', {
    id: 'rad1',
    type: 'radio',
    name: 'rad'
  })
  div.appendChild(radio)

  label = ce('label', {
    for: 'rad1'
  })
  $(label).html(getStr('ChoixOutDlg2'))
  div.appendChild(label)
  radio = ce('input', {
    id: 'rad2',
    type: 'radio',
    name: 'rad',
    style: 'margin-left:20px;'
  })
  div.appendChild(radio)
  label = ce('label', {
    for: 'rad2'
  })
  $(label).html(getStr('ChoixOutDlg3'))
  div.appendChild(label)
  if (this.docNiv.itemsCochesInterdits) $('#rad2').attr('checked', 'checked')
  else $('#rad1').attr('checked', 'checked')
  // Dessous l'arbre dans un div
  tr = ce('tr')
  tabPrincipal.appendChild(tr)
  div = ce('div', {
    id: 'div',
    style: 'display:inline-block;width:550px;height:350px;vertical-align:top;overflow:auto;border:1px solid black;margin-top: 5px;'
  })
  tr.appendChild(div)
  $(div).jstree({
    plugins: ['wholerow', 'checkbox', 'types'],
    core: { // types pour pouvoir avoir des user defined icones
      check_callback: true
    }
  })
  this.tree = $(div).jstree(true)
  this.idroot = this.tree.create_node('#', getStr('ChoixOutils'))
  this.addToolsTopBar()
  const tab = ['Points', 'Droites', 'Segments', 'Cercles', 'Polys', 'Marques', 'Lieux', 'Transf', 'Mes', 'Disp', 'Calculs', 'Surfaces']
  for (i = 0; i < tab.length; i++) this.addTools(tab[i])
  this.addTools('Divers', true)

  // Création de la boîte de dialogue par jqueryui
  this.create('ChoixOutils', 600)
  this.tree.open_node(this.idroot)
}

ChoixOutilsDlg.prototype = new MtgDlg()

/**
 * Fonction rajoutant à la racine de l'arbre une nouvelle branche avec comme texte le name de app.expandableBarName
 * et comme noeuds enfants les noms des outils de cette ExpandableBar
 * @param expandableBarName Le name de la barre d'outils
 * @param {boolean} bDivers  true pour le dernier outil proposant des outils divers
 */
ChoixOutilsDlg.prototype.addTools = function (expandableBarName, bDivers = false) {
  let id2, id3, tool
  const app = this.app
  const eb = app['bar' + expandableBarName]
  const tab = eb.tab
  const id = this.tree.create_node(this.idroot, getStr(expandableBarName))
  const size = tab.length
  const itemsCochesInterdits = this.docNiv.itemsCochesInterdits
  for (let i = 0; i < size; i++) {
    tool = app['outil' + tab[i]]
    if (tool.toolName.indexOf('Add') === 0) {
      if (this.hasTools(tool)) {
        if (!bDivers) id2 = this.tree.create_node(id, { text: ' ' + getStr('Add') })
        for (let j = 0; j < tool.toolArray.length; j++) {
          const tool2 = app['outil' + tool.toolArray[j]]
          if (app.levels[this.niv].toolDispo(tool2.toolIndex)) {
            id3 = this.tree.create_node(bDivers ? id : id2, getStr(tool2.toolName))
            const b = this.docNiv.toolDispo(tool2.toolIndex)
            if ((!itemsCochesInterdits && b) || (itemsCochesInterdits && !b)) { this.tree.select_node(id3) } else this.tree.deselect_node(id3)
            this[id3] = tool2.toolIndex
          }
        }
      }
    } else if (app.levels[this.niv].toolDispo(tool.toolIndex)) {
      const tool2 = app['outil' + tab[i]]
      const hasIcon = tool2.hasIcon
      if (hasIcon) {
        const b = this.docNiv.toolDispo(tool2.toolIndex)
        import(`src/images/outil${tab[i]}.png`).then(({ default: img }) => {
          id2 = this.tree.create_node(id, {
            text: ' ' + getStr(tool2.toolName),
            // pour que ça fonctionne en CORS il faut une url absolue
            icon: getAbsolutePath(img)
          })
          if ((!itemsCochesInterdits && b) || (itemsCochesInterdits && !b)) { this.tree.select_node(id2) } else this.tree.deselect_node(id2)
          this[id2] = tool2.toolIndex // Pour pouvoir associer à chaque branche le nom de l'outil correspondant
        }).catch(error => console.error(error))
      } else {
        const b = this.docNiv.toolDispo(tool2.toolIndex)
        id2 = this.tree.create_node(id, getStr(tool2.toolName))
        if ((!itemsCochesInterdits && b) || (itemsCochesInterdits && !b)) { this.tree.select_node(id2) } else this.tree.deselect_node(id2)
        this[id2] = tool2.toolIndex // Pour pouvoir associer à chaque branche le nom de l'outil correspondant
      }
    }
  }
}

ChoixOutilsDlg.prototype.addToolsTopBar = function () {
  const app = this.app
  const id = this.tree.create_node(this.idroot, getStr('ToolsBarHor'))
  const tab = ['ModifObjGraph', 'ZoomPlus', 'ZoomMoins', 'ModifObjNum', 'Palette', 'CopierStyle', 'ModeTrace', 'ModePointsAuto', 'UseLens', 'Recalculer', 'Gomme', 'Rideau',
    'TranslationFigure', 'ModeAutoComplete', 'ExecutionMacro', 'Protocole', 'Help', 'ToggleToolsAdd']
  const size = tab.length
  const itemsCochesInterdits = this.docNiv.itemsCochesInterdits
  for (let i = 0; i < size; i++) {
    const tool2 = app['outil' + tab[i]]
    if (tool2) {
      import(`src/images/outil${tab[i]}.png`)
        .then(({ default: img }) => {
          const id2 = this.tree.create_node(id, {
            text: ' ' + getStr(tool2.toolName),
            // pour que ça fonctionne en CORS il faut une url absolue
            icon: getAbsolutePath(img)
          })
          const b = this.docNiv.toolDispo(tool2.toolIndex)
          if ((!itemsCochesInterdits && b) || (itemsCochesInterdits && !b)) {
            this.tree.select_node(id2)
          } else this.tree.deselect_node(id2)
          this[id2] = tool2.toolIndex // Pour pouvoir associer à chaque branche le nom de l'outil correspondant
        })
        .catch(error => console.error(error))
    }
  }
}
/**
 * Fonction renvoyant true si l'outil addTool de type OutilAdd a au moins un outil à mettre dans la liste
 * @param addTool
 * @returns {boolean}
 */
ChoixOutilsDlg.prototype.hasTools = function (addTool) {
  const app = this.app
  for (let j = 0; j < addTool.toolArray.length; j++) {
    const tool2 = app['outil' + addTool.toolArray[j]]
    if (app.levels[this.niv].toolDispo(tool2.toolIndex)) return true
  }
  return false
}

ChoixOutilsDlg.prototype.OK = function () {
  const app = this.app
  const self = this
  let b; let doc
  const selectedData = []
  const selectedIndexes = this.tree.get_selected(true)

  $.each(selectedIndexes, function (index) {
    b = self[selectedIndexes[index].id] // b est undefined pour les noeuds racines des branches
    if (b) selectedData.push(self[selectedIndexes[index].id])
  })
  const checked = $('#rad2').prop('checked')
  this.doc.setIdMenus(app, checked, selectedData, this.niv)
  // Si on est en mode électron et si la case est cochée, on appelle setLevel de la page index.html
  if ((app.electron || app.pwa) && this.persDispo) {
    if ($('#cb').prop('checked')) {
      doc = new CMathGraphDoc('', false, false)
      doc.dimf = app.dimf
      doc.setIdMenus(app, checked, selectedData, this.niv)
      if (app.electron) setLevel(doc.getBase64Code()) // eslint-disable-line no-undef
      else localStorage.setItem('level', doc.getBase64Code())
      // setLevel est défini dans index.html
      doc = null
    }
  }
  this.destroy()
}