v2.3.1: corrige campo de CSS personalizado travado (Monaco criado oculto)

O editor era criado dentro de uma div com d-none: com display:none o
Monaco mede 0x0 e nasce sem área editável, enquanto o textarea ficava
oculto e disabled — resultado, campo impossível de editar.

- container passa a ser exibido ANTES do create (dimensões reais),
  mais layout() explícito e automaticLayout para relayout no resize;
- _force_default_lang evita o caminho de clonagem de linguagem do core
  (que quebra se a linguagem base não estiver registrada);
- textarea deixa de ser disabled: fica só oculto, com o valor do editor
  copiado nos eventos submit E formdata (form.submit() programático não
  dispara submit; formdata cobre os dois casos) — sem risco de perder a
  edição silenciosamente no POST;
- se o create falhar, rollback para o textarea comum.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Claude 2026-07-31 13:11:16 -03:00
parent e42eb2c798
commit b409b65895
2 changed files with 37 additions and 16 deletions

View file

@ -1,6 +1,6 @@
<?php
define('PLUGIN_BUTTERFLY_VERSION', '2.3.0');
define('PLUGIN_BUTTERFLY_VERSION', '2.3.1');
// Minimal GLPI version, inclusive
define("PLUGIN_BUTTERFLY_MIN_GLPI_VERSION", "11.0.0");

View file

@ -257,30 +257,46 @@ class Config extends \CommonDBTM {
);
echo $value;
echo '</textarea>';
echo '<div id="' . $containerId . '" class="d-none" style="height: 300px; border: 1px solid #dcdcdc"></div>';
echo '<div id="' . $containerId . '" class="d-none butterfly-css-monaco"></div>';
echo \Html::scriptBlock('
$(function() {
if (window.GLPI === undefined || window.GLPI.Monaco === undefined) {
return; // sem Monaco nesta página — fica o textarea
}
var taId = ' . json_encode($textareaId, JSON_HEX_TAG | JSON_HEX_AMP) . ';
var $ta = $("#" + ' . json_encode($textareaId, JSON_HEX_TAG | JSON_HEX_AMP) . ');
var containerId = ' . json_encode($containerId, JSON_HEX_TAG | JSON_HEX_AMP) . ';
var fieldName = ' . json_encode($fullName, JSON_HEX_TAG | JSON_HEX_AMP) . ';
window.GLPI.Monaco.createEditor(containerId, "scss", $("#" + taId).val(), []).then(() => {
$("#" + containerId).removeClass("d-none");
$("#" + taId).addClass("d-none").prop("disabled", true);
$("#" + containerId).closest("form").on("formdata", (e) => {
const editors = window.monaco.editor.getEditors().filter(
(editor) => editor._domElement.id === containerId
);
if (editors.length) {
e.originalEvent.formData.delete(fieldName);
e.originalEvent.formData.append(fieldName, editors[0].getValue());
}
var $container = $("#" + containerId);
// O container precisa estar visível ANTES do create: com display:none
// o Monaco mede 0x0 e nasce sem área editável
$container.removeClass("d-none");
$ta.addClass("d-none");
window.GLPI.Monaco.createEditor(containerId, "scss", $ta.val(), [], {
_force_default_lang: true,
automaticLayout: true,
minimap: { enabled: false },
scrollBeyondLastLine: false,
fontSize: 13,
tabSize: 3
}).then((editor) => {
editor.editor.layout();
var $form = $container.closest("form");
// textarea segue habilitado (só oculto) e recebe o valor do editor.
// submit não dispara em form.submit() programático, por isso o
// formdata também: ele roda na montagem da entry list nos dois casos
$form.on("submit", function() {
$ta.val(editor.editor.getValue());
});
$form.on("formdata", function(e) {
$ta.val(editor.editor.getValue());
e.originalEvent.formData.set($ta.attr("name"), editor.editor.getValue());
});
}).catch(() => {
// editor falhou — mantém o textarea funcional
// editor falhou — volta para o textarea comum
$container.addClass("d-none");
$ta.removeClass("d-none");
});
});
');
@ -333,6 +349,11 @@ class Config extends \CommonDBTM {
border: 1px solid #eee;
font-family: monospace;
}
.butterfly-css-monaco {
width: 100%;
height: 300px;
border: 1px solid #dcdcdc;
}
.butterfly-themeselect-container .select2-selection__rendered,
.butterfly-themeselect-dropdown .select2-results__option {
height: 80px !important;