Changing the view page of the universal list item in boxed Bitrix24

Hello.



If you have ever worked with universal lists in Bitrix24, then you are probably aware that the detail page of an element is completely identical to the edit page. The only difference is that if the user has read-only permissions, then the page will not have the Save and Apply buttons. Agree, not the most pleasant interface.







And therefore, when at work it became necessary to use universal lists, I decided to change the detailed view page, since we are using a box, and the possibilities for customization are simply unlimited.







24 , , , .



local , . .



— DOM- Javascript.



In fact, we just need to change the link to the detailed page in the list table:







However, in reality, this is not so easy to implement, since you need to go into the component responsible for displaying universal lists and edit the link there.



Therefore, we will take a different path - through Javascript we will open the page in the slider using the SidePanel bitrix library.



There are two ways to do this - in init.php and in your own module. You also need to register your JS library.



And although the second method is more convenient, I will show you the first one, and at the end of the article I will give a link to my module.



So let's go. All actions must be performed in the local folder.



First you need to create a separate folder where our library will be stored. Let's call it, for example, viewer, and it will have the following structure:



/viewer 
-/js
--viewer.js //  js-
-include.php // ,      init.php


Let's stop here a little. For the php code, I created a separate file, which I will then include in init.php so as not to litter the latter.



Let's now register our library using the old core CJSCore :: RegisterExt method :



// include.php

// ..    js- viewer,     
CJSCore::RegisterExt('elementviewer', [ 
    'js' => '/local/viewer/js/viewer.js', //   
    'rel' => ['SidePanel'] // 
]);


It remains only to connect this library on the page of universal lists with the CJSCore :: Init method , and, it would seem, it's in the bag - you can start writing the library itself.



However, not everything is so simple, since before connecting, you need to check that we are on the right page. It is better to do this using regular expressions, since the id of the list in the address can change



// include.php

$pattern = '/\/lists\/(\d+)\/view\//'; //     ,  (\d+) = id 
$server = Bitrix\Main\Context::getCurrent()->getServer(); //  Server,     

if(preg_match($pattern, $server->getRequestUri())) {
       CJSCore::Init(['elementviewer']); //  
}


So, the library is connected, it remains to write it. To do this, create a viewer.js file (if you haven't created it before) and first of all declare a namespace using the BX.namespace function :



const ElementViewer = BX.namespace('Viewer');


Now all variables and functions can be declared in the following way:



ElementViewer.init = function() {

}


In order not to write all the code in one function, let's break it down into smaller ones for convenience.



First of all, we need to find the node on the page that contains the link to the detail page. To do this, we will use the BX.findChildren function , which should return us a list of all objects containing links to the detail page:



ElementViewer.findCell = function () {
    return BX.findChildren(document, {
        class: 'main-grid-cell-content' // css-    
    }, true);
}


At the same time, we will write a function that will extract the id of the list and element from the link for further work:



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])
        };
    }
}


Let's go back to BX.findChildren. The peculiarity of this function is that it returns a list of all objects with the specified css class, and it is not a fact that this will be a link. Therefore, we need to check, and only after that cancel the link open event and open the slider:



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); //  
                })
            }
        }
    });

}


It remains for us to write the last function that will open the slider. To do this, we use the SidePanel library :



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
    });
}


Well, the library is written, it remains to call the init function after connecting. To do this, let's return to include.php, where the page address is checked:



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);
}


The final touch remains - to include our code in init.php:



// init.php

$file = $_SERVER['DOCUMENT_ROOT'] . '/local/path/to/viewer/include.php';

if(file_exists($file)) {
   require $file;
}


If everything is done correctly, then when you click on the element of the universal list, a slider will open:











Finally, as promised, a link to a module that implements the same thing.



Thank you for attention.



All Articles