Template source: drf-yasg/swagger-ui.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title>{% block title %}{{ title }}{% endblock %}</title>

    {% block extra_head %}
        {# -- Add any extra HTML heads tags here - except scripts and styles -- #}
    {% endblock %}

    {% block favicon %}
        {# -- Maybe replace the favicon -- #}
        <link rel="icon" type="image/png" href="{% static 'drf-yasg/swagger-ui-dist/favicon-32x32.png' %}"/>
    {% endblock %}

    {% block main_styles %}
        <link rel="stylesheet" type="text/css" href="{% static 'drf-yasg/style.css' %}"/>
        <link rel="stylesheet" type="text/css" href="{% static 'drf-yasg/swagger-ui-dist/swagger-ui.css' %}">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
              integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1"
              crossorigin="anonymous">
        <!-- JavaScript Bundle with Popper -->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"
                integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"
                crossorigin="anonymous"></script>

    {% endblock %}
    {% block extra_styles %}
        {# -- Add any additional CSS scripts here -- #}
    {% endblock %}
</head>

<body class="">

{% block extra_body %}

    {# -- Add any header/body markup here (rendered BEFORE the swagger-ui/redoc element) -- #}
{% endblock %}



            <div class="left-bar-wrapper">
            <div class="left-bar">
                        <div class="left-bar-logo">
                <img src="https://freecast.com/wp-content/uploads/2020/02/freecast-2016-logo-06.png" alt="logo">
                </div>

            <div class="left-menu " style="opacity: 0">

                <br>
            </div>
            </div>
    </div>



<div class="container-fluid">
<div class="row">



    <div class="col-md-2">




    </div>

    <div class="col-md-10 right-bar">
        <div class="swagger-body">
            <div id="swagger-ui"></div>
        </div>
    </div>

</div>
</div>

{% block footer %}
    {# -- Add any footer markup here (rendered AFTER the swagger-ui/redoc element) -- #}
{% endblock %}

<script id="swagger-settings" type="application/json">{{ swagger_settings | safe }}</script>
<script id="oauth2-config" type="application/json">{{ oauth2_config | safe }}</script>

{% block main_scripts %}
    <script src="{% static 'drf-yasg/swagger-ui-dist/swagger-ui-bundle.js' %}"></script>
    <script src="{% static 'drf-yasg/swagger-ui-dist/swagger-ui-standalone-preset.js' %}"></script>
    <script src="{% static 'drf-yasg/insQ.min.js' %}"></script>
    <script src="{% static 'drf-yasg/immutable.min.js' %}"></script>
    <script src="{% static 'drf-yasg/url-polyfill.min.js' %}"></script>
    <script src="{% static 'drf-yasg/swagger-ui-init.js' %}"></script>
{% endblock %}
{% block extra_scripts %}
    {# -- Add any additional scripts here -- #}
{% endblock %}

<a id="oauth2-redirect-url" href="{% static 'drf-yasg/swagger-ui-dist/oauth2-redirect.html' %}" class="hidden"></a>

{% if USE_SESSION_AUTH %}
    <div id="django-session-auth" class="hidden">
        {% block session_auth_button %}
            {% csrf_token %}

            {% block user_context_message %}
                {% if request.user.is_authenticated %}
                    <div class="hello">
                        <span class="django-session">Django</span> <span
                            class="label label-primary">{{ request.user }}</span>
                    </div>
                {% endif %}
            {% endblock %}

            {% if request.user.is_authenticated %}
                <div class='btn authorize'>
                    <a id="auth" class="header__btn" href="{{ LOGOUT_URL }}?next={{ request.path }}" data-sw-translate>
                        {% block django_logout_message %}
                            Django Logout
                        {% endblock %}
                    </a>
                </div>
            {% else %}
                <div class='btn authorize'>
                    <a id="auth" class="header__btn" href="{{ LOGIN_URL }}?next={{ request.path }}" data-sw-translate>
                        {% block django_login_message %}
                            Django Login
                        {% endblock %}
                    </a>
                </div>
            {% endif %}
        {% endblock %}
    </div>
{% endif %}
</body>


<script>

    const invalidProtocolRegex = /^(%20|\s)*(javascript|data|vbscript)/im;
    const ctrlCharactersRegex = /[^\x20-\x7EÀ-ž]/gim;
    const urlSchemeRegex = /^([^:]+):/gm;
    const relativeFirstCharacters = [".", "/"];

    function isRelativeUrlWithoutProtocol(url){
      return relativeFirstCharacters.indexOf(url[0]) > -1;
    }

    function sanitizeUrl(url){
      if (!url) {
        return "about:blank";
      }

      const sanitizedUrl = url.replace(ctrlCharactersRegex, "").trim();

      if (isRelativeUrlWithoutProtocol(sanitizedUrl)) {
        return sanitizedUrl;
      }

      const urlSchemeParseResults = sanitizedUrl.match(urlSchemeRegex);

      if (!urlSchemeParseResults) {
        return sanitizedUrl;
      }

      const urlScheme = urlSchemeParseResults[0];

      if (invalidProtocolRegex.test(urlScheme)) {
        return "about:blank";
      }

      return sanitizedUrl;
    }

    function setAttributes(el, attrs) {
        for (var key in attrs) {
            el.setAttribute(key, attrs[key]);
        }
    }

    let xhr = new XMLHttpRequest();
    xhr.open('GET', '/swagger/?format=openapi');
    xhr.send()
    xhr.onload = function () {
        if (xhr.status !== 200) { // анализируем HTTP-статус ответа, если статус не 200, то произошла ошибка
            alert(`Ошибка ${xhr.status}: ${xhr.statusText}`); // Например, 404: Not Found
        } else { // если всё прошло гладко, выводим результат
            let data = JSON.parse(xhr.response)
            let anchor_link = window.location.hash
            console.log(data)
            let tags = {};
            let paths = data.paths
            var c = 0
            for (var prop in paths) {
                if (paths.hasOwnProperty(prop)) {
                    let path = paths[prop]

                    let paths_tags = []

                    if (path['get']) {
                        paths_tags.push(path['get']['tags'])
                    }

                    if (path['post']) {
                        paths_tags.push(path['post']['tags'])
                    }
                    c += 1;

                    paths_tags.forEach(tag => {
                        if (!(tag in tags)) {
                            tags[tag] = []
                        }
                        tags[tag].push(path)
                    })
                }
            }
            console.log(c)

            let tagElems = []
            let leftMenu = document.querySelector('.left-menu')

            for (let tagName in tags) {
                if (tags.hasOwnProperty(tagName)) {

                    let tagElem = document.createElement('div');
                    let id = tagName.replace(/\W/g,'_');
                    setAttributes(tagElem, {'class': 'left-menu-item'})

                    let link = document.createElement('h3');
                    setAttributes(
                        link,
                        {'data-bs-toggle': 'collapse', 'data-bs-target': "#" + id, 'type': 'button', 'aria-expanded': "false",  'aria-controls': "collapseExample"}
                    )

                    link.innerHTML = '<strong>' + tagName + "</strong>";

                    let collapseList = document.createElement('div');
                    setAttributes(collapseList, {'id': id, 'class': 'collapse pl-2 left-menu-inner'})

                    let paths = tags[tagName]

                    paths.forEach(
                        path => {
                            for (let methodName in path){
                                if (methodName  == 'post' || methodName == 'get') {


                                    let item = path[methodName]
                                    let pathLink = document.createElement('a')


                                    setAttributes(pathLink, {
                                        'href': '#operations-' + tagName + "-" + sanitizeUrl(item.operationId),
                                        'class': 'left-menu-inner-item'
                                    })
                                    let name = item.summary || item.operationId;
                                    pathLink.innerHTML = name
                                    collapseList.appendChild(pathLink)
                                }
                            }

                        }
                    )

                    tagElem.appendChild(link);
                    tagElem.appendChild(collapseList)
                    leftMenu.appendChild(tagElem)


                }
            }
            let count = 15
            if (anchor_link.indexOf('#') !== -1) {
                anchor_link = anchor_link.substring(1)
                var checkLoaded = setInterval(function () {
                    if (count === 0){
                       clearInterval(checkLoaded);
                    }
                    if (document.getElementById(anchor_link) != null) {
                        clearInterval(checkLoaded);
                        document
                        .getElementById(anchor_link)
                        .scrollIntoView({behavior: "smooth"});
                    }
                    count -= 1
                }, 1000); // check every 100ms

            }

        }

    }
    // It takes the document a sec to load the swagger stuff loop until we find it

    setTimeout(
        function (){
            var elem = document.querySelector('.left-menu');
            elem.style.opacity = 1
        },
        15000
    )
</script>




<style>
    body{
    }
    .left-bar {

        margin-right: 0;

        color: #1b1b1b;
        padding-right: 0;
        font-size: 12px;

        height: 100vh;
        position: fixed;
        top: 0;
        left: 0;
        width: 16.6666666667%;
        overflow-y: auto;
        border-right: 1px solid #eee;

    }
    .left-bar-logo{

        padding: 8px;
        text-align: center;
    }
    .left-bar-logo img{
        max-width: 50%;
    }


    .right-bar {
        margin-left: 0;
        padding: 0;
        background-color: #fff;
    }
    .left-menu{

    }
    .left-menu-item{

        padding: 2px 5px;
        padding-left: 10px;



    }
    .left-menu-item h3{
        font-size: 14px;

    }
    .left-menu-inner{


        font-weight: 500;

    }

    .left-menu-inner-item{
        display: block;

        padding: 2px 2px 4px;
        padding-left: 10px;
        text-decoration: none;
        color: #0a0a0a;

    }
    .left-menu-inner-item:hover{

    }
    .fixedrow{
        position: fixed;
        left: 0;
        top: 0;
        width: 100%;
    }
</style>
</html>