Se você já trabalhou com listas universais no Bitrix24, provavelmente sabe que a página de detalhes de um elemento é completamente idêntica à página de edição. A única diferença é que, se o usuário tiver permissões somente leitura, a página não terá os botões Salvar e Aplicar. Concordo, não é a interface mais agradável.

E por isso, quando no trabalho tornou-se necessário o uso de listas universais, resolvi mudar a página de visualização detalhada, já que estamos usando uma caixa, e as possibilidades de personalização são simplesmente ilimitadas.
24 , , , .
local , . .
— DOM- Javascript.
Na verdade, só precisamos alterar o link para a página detalhada na tabela de lista:

No entanto, na realidade, isso não é tão fácil de implementar, uma vez que você precisa ir para o componente responsável por exibir listas universais e editar o link lá.
Portanto, tomaremos um caminho diferente - através do Javascript abriremos a página no controle deslizante usando a biblioteca bitrix SidePanel.
Existem duas maneiras de fazer isso - em init.php e em seu próprio módulo. Você também precisa registrar sua biblioteca JS.
E embora o segundo método seja mais conveniente, mostrarei o primeiro, e no final do artigo darei um link para o meu módulo.
Então vamos. Todas as ações devem ser realizadas na pasta local.
Primeiro você precisa criar uma pasta separada onde nossa biblioteca será armazenada. Vamos chamá-lo, por exemplo, de visualizador, e ele terá a seguinte estrutura:
/viewer
-/js
--viewer.js // js-
-include.php // , init.php
Vamos parar um pouco aqui. Para o código php, criei um arquivo separado, que irei incluir no init.php para não sujar o último.
Vamos agora registrar nossa biblioteca usando o antigo método central CJSCore :: RegisterExt :
// include.php
// .. js- viewer,
CJSCore::RegisterExt('elementviewer', [
'js' => '/local/viewer/js/viewer.js', //
'rel' => ['SidePanel'] //
]);
Resta apenas conectar esta biblioteca na página de listas universais com o método CJSCore :: Init e, ao que parece, está na bolsa - você pode começar a escrever a própria biblioteca.
Porém, nem tudo é tão simples, pois antes de conectar, você precisa verificar se estamos na página certa. É melhor fazer isso usando expressões regulares, uma vez que o id da lista no endereço pode mudar
// include.php
$pattern = '/\/lists\/(\d+)\/view\//'; // , (\d+) = id
$server = Bitrix\Main\Context::getCurrent()->getServer(); // Server,
if(preg_match($pattern, $server->getRequestUri())) {
CJSCore::Init(['elementviewer']); //
}
Então, a biblioteca está conectada, falta escrever. Para fazer isso, crie um arquivo viewer.js (se ainda não o tiver criado) e, antes de mais nada, declare um namespace usando a função BX.namespace :
const ElementViewer = BX.namespace('Viewer');
Agora todas as variáveis e funções podem ser declaradas da seguinte maneira:
ElementViewer.init = function() {
}
Para não escrever todo o código em uma função, vamos dividi-lo em outros menores por conveniência.
A primeira coisa que precisamos fazer é localizar o nó na página que contém o link para a página de detalhes. Para fazer isso, usaremos a função BX.findChildren , que deve nos retornar uma lista de todos os objetos que contêm links para a página de detalhes:
ElementViewer.findCell = function () {
return BX.findChildren(document, {
class: 'main-grid-cell-content' // css-
}, true);
}
Ao mesmo tempo, escreveremos uma função que extrairá o id da lista e o elemento do link para trabalhos futuros:
ElementViewer.pattern = '/lists/(\\d+)/element/0/(\\d+)'; // , = id , = id .
ElementViewer.extractListData = function (url) {
let match = url.match(this.pattern); //
if(match) {
return {
list_id: Number(match[1]),
element_id: Number(match[2])
};
}
}
Vamos voltar para BX.findChildren. A peculiaridade desta função é que ela retorna uma lista de todos os objetos com a classe css especificada, e não é um fato que este será um link. Portanto, precisamos verificar, e somente depois disso, cancelar o evento de abertura do link e abrir o controle deslizante:
ElementViewer.init = function (sliderUrl) {
const cell = this.findCell();
cell.forEach(item => {
let itemChild = item.children;
let child = itemChild[0];
if(child && child.tagName === 'A') {
const listData = this.extractListData(child.toString()); // id
if(listData !== undefined) {
child.addEventListener('click', (e) => {
e.preventDefault(); //
this.openSlider(sliderUrl, listData.list_id, listData.element_id); //
})
}
}
});
}
Resta-nos escrever a última função que irá abrir o controle deslizante. Para fazer isso, usamos a biblioteca SidePanel :
ElementViewer.openSlider = function (sliderUri, listId, elementId) {
// POST, id
let sliderParams = {
list_id: listId,
element_id: elementId
}
return BX.SidePanel.Instance.open(sliderUri, {
allowChangeHistory: false,
cacheable: false,
requestMethod: 'POST',
requestParams: sliderParams
});
}
Bem, a biblioteca está escrita, resta chamar a função init após a conexão. Para fazer isso, vamos retornar a include.php, onde o endereço da página é verificado:
if(preg_match($pattern, $server->getRequestUri())) {
CJSCore::Init(['elementviewer']); //
$asset = Bitrix\Main\Page\Asset::getInstance();
$script = '<script>BX.ready(function() {
ElementViewer.init();
})</script>';
$asset->addString($script);
}
O toque final permanece - incluir nosso código em init.php:
// init.php
$file = $_SERVER['DOCUMENT_ROOT'] . '/local/path/to/viewer/include.php';
if(file_exists($file)) {
require $file;
}
Se tudo for feito corretamente, ao clicar no elemento da lista universal, um controle deslizante será aberto:


Finalmente, como prometido, um link para um módulo que implementa a mesma coisa.
Obrigado pela atenção.