PageSourceSearch

https://russian-literature.org/nonstatic/scripts/treework.js

js russian-literature.org collected 2026-10-02 17:57:31 UTC 45,582 bytes, 1,133 lines download raw bytes

1/**
2 * Функции для работы с деревом
3 * Created by nikita on 16.05.14.
4 */
5
6/**
7 * Хранит объект дерева
8 */
9var treeDatas = [],
10/**
11 * Хранит посещенные страницы в объектах дерева
12 * @type {{}}
13 */
14nodePages = {},
15activate = false;
16
17var title;
18
19var searchByIndexWordValue;
20var searchByIndexLetterValue;
21
22/**
23 * Функции, выполняемые при загрузке страницы
24 */
25$(document).ready(function () {
26    searchByIndexWordValue = null;
27    searchByIndexLetterValue = null;
28    title = $('title').html();
29
30    //Функция не срабатывает при наличии в дереве класса indexFilterLoadAllButton (sobr)
31    $('.tree-container').each(function() {
32        if ($(this).find('.indexFilterLoadAllButton').length === 0) {
33            var me = $(this),
34                showTree = me.attr('data-show-tree');
35            if (showTree === 'true') {
36                initTreeFromNode($(this));
37            }
38        }
39    });
40
41    $('body').on('click', '.children-tree-tab', function () {
42       var tree = $('#' + $(this).attr('aria-controls')).find('.tree-container'),
43           showTree = tree.attr('data-show-tree');
44        if (showTree === 'false') {
45            tree.attr('data-show-tree', 'true');
46            initTreeFromNode(tree);
47        }
48
49    });
50
51    $('.tree-letter').click(function () {
52        setAlphabet($(this));
53    });
54
55    $('.tree-letter-index').click(function () {
56        setIndexAlphabet($(this));
57    });
58
59
60    $('.indexFilterInput').on('keyup input', function (event) {
61        var keycode = (event.keyCode ? event.keyCode : event.which);
62        if(keycode === 13) {
63            setIndexInputSearch($(this).val().trim());
64        }
65    });
66
67    $('.indexFilterInputButton').click(function () {
68        setIndexInputSearch($(this).siblings(".indexFilterInput").first().val().trim());
69    });
70
71    //Сброс поиска
72    $('.indexFilterClearButton').click(function () {
73        $(this).siblings(".indexFilterInput").first().val("");
74        searchByIndexWordValue = (typeof searchByIndexWordValue === 'undefined') ? null : null;
75        searchByIndexLetterValue = (typeof searchByIndexLetterValue === 'undefined') ? null : null;
76        setIndexInputSearch("")
77    });
78
79    //Загрузить все
80    $('.indexFilterLoadAllButton').click(function () {
81        $(this).siblings(".indexFilterInput").first().val("");
82
83        var filterTitle = $('.index-filter-title-container');
84        filterTitle.text("");
85
86        searchByIndexWordValue = (typeof searchByIndexWordValue === 'undefined') ? null : null;
87        searchByIndexLetterValue = (typeof searchByIndexLetterValue === 'undefined') ? null : null;
88        setIndexInputSearch("")
89    });
90
91    $('.tree-mode-button').on('click', function () {
92        changeTreeMode($(this));
93    });
94
95    $(document).on('contextmenu', '.sobr-expand-annotation', function (event) {
96        event.preventDefault();
97        $(this).siblings('.sobr-expandable-annotation').first().toggleClass("sobr-hidden");
98        return false;
99    });
100
101    $(document).on('contextmenu', '.sobr-expandable-annotation', function (event) {
102        event.preventDefault();
103        $(this).toggleClass("sobr-hidden");
104        return false;
105    });
106
107    $(document).on('contextmenu', '.jstree-anchor', function (event) {
108        if($(this).find('.sobr-expandable-annotation').size() > 0) {
109            event.preventDefault();
110            $(this).children('.sobr-expandable-annotation').first().toggleClass("sobr-hidden");
111            return false;
112        }
113    });
114});
115
116function Tree(componentId, searchIndex, page, parentId, objectType, selectedObjectType, imageTree) {
117    var object = this,
118        isTreeOfObject = false,
119        treeContainer = $('#tree-container-' + componentId),
120        tabId = treeContainer.attr('data-tab-id'),
121        objectId = treeContainer.attr('data-object-id'),
122        searchByPages = treeContainer.attr('data-search-by-pages'),
123        randomImageTree = treeContainer.attr('data-component-random-image-tree'),
124        orderNumber = treeContainer.attr('data-sort-condition-number'),
125        showPageList = true,
126        dataParentId = treeContainer.attr('data-parent-id'),
127        alphabet = treeContainer.attr('data-alphabet'),
128        count = treeContainer.attr('data-count'),
129        customSearchDialog = $('.custom-search-dialog'),
130        paginationTop = treeContainer.attr('data-paging-top'),
131
132        searchByCompleteWork = treeContainer.attr('data-search-by-content-index'),
133        searchByIndexPublication = treeContainer.attr('data-search-by-content-index-publication'),
134        completeWorkId = treeContainer.attr('data-search-by-content-index-completework-id'),
135        paginationBottom = treeContainer.attr('data-paging-bottom');
136
137    if (dataParentId === undefined || dataParentId == "") {
138        dataParentId = null;
139    } else {
140        showPageList = false;
141    }
142    if (parentId !== null && parentId != "") {
143        dataParentId = parentId;
144        isTreeOfObject = true;
145    }
146
147    /**
148     * Инициализирует дерево объектов. Если дерево уже существует, уничтожает его
149     * и создает заново
150     * @param componentId - id компоненты поиска
151     * @param searchIndex - поисковый индекс компоненты
152     * @param page - страница со списком объектов
153     */
154    this.initTree = function initTree(page) {
155        var ls = $.cookie('ls'),
156            url,
157            tree = treeDatas["" + componentId];
158        if (searchByCompleteWork === 'true') {
159            if(searchByIndexPublication === 'true') {
160                url = contextPath + '/ajax/searchByCompleteWorkPubl/' + searchIndex;
161            } else {
162                url = contextPath + '/ajax/searchByCompleteWork/' + searchIndex;
163            }
164        } else
165        if ((objectId === null || objectId === "") && searchByPages === 'true') {
166            url = contextPath + '/ajax/searchByPages/' + searchIndex;
167        } else if (randomImageTree === 'true') {
168            url = contextPath + '/ajax/randomImageTree/' + searchIndex;
169        } else {
170            url = contextPath + '/ajax/tree/' + searchIndex;
171        }
172
173        if (tree !== undefined) {
174            tree.jstree("destroy");
175        }
176
177        tree = $('#tree-' + componentId);
178        treeDatas["" + componentId] = tree;
179        tree.jstree({
180            core: {
181                strings : {
182                    'Loading ...' : 'Загрузка ...'
183        			},
184                data: {
185                    type: (searchByCompleteWork === 'true') ? "POST" : "GET",
186                    url: url,
187                    data: function (node) {
188                        return {
189                            page: page,
190                            nPage: node === undefined || node === null || nodePages[node.id] === undefined
191                                ? 1 : nodePages[node.id],
192                            size: ls,
193                            id: node === undefined || node === null || node.id === '#' ? 0 : node.id,
194                            parentId: dataParentId,
195                            objectType: objectType,
196                            orderNumber: orderNumber,
197                            showPageList: showPageList,
198                            count: count,
199                            alphabet: alphabet,
200                            tabId: tabId,
201                            completeWorkId: completeWorkId === undefined || completeWorkId === null || completeWorkId < 0 ? -1 : completeWorkId,
202                            searchByIndexWordValue: searchByCompleteWork === 'true'
203                                && searchByIndexWordValue !== undefined ? searchByIndexWordValue : null,
204                            searchByIndexLetterValue: searchByCompleteWork === 'true'
205                                 && searchByIndexLetterValue !== undefined ? searchByIndexLetterValue : null
206                        };
207                    }
208                }
209            }
210        }).on('activate_node.jstree', function (e, data) {
211
212            // setMetaKey('');
213
214            if (activate && parentId === null) {
215                if (tree.jstree('is_open', '#' + data.node.id)) {
216                    tree.jstree('close_node', '#' + data.node.id);
217                } else {
218                    tree.jstree('open_node', '#' + data.node.id);
219                }
220            }
221
222            if (activate) {
223                if (customSearchDialog.css('display') === 'block') {
224                    customSearchDialog.modal({backdrop:false}).modal('hide');
225                }
226            }
227
228            activate = true;
229            if (data.node !== undefined && data.node !== null &&
230                data.node.a_attr !== undefined && data.node.a_attr !== null &&
231                data.node.a_attr["clickUrl"] !== undefined && data.node.a_attr["clickUrl"] !== null) {
232                if (data.node.a_attr["nonClickUrl"] === undefined || data.node.a_attr["nonClickUrl"] === null) {
233                    var url = data.node.a_attr["clickUrl"];
234                    openUrl(url.startsWith('www') || url.startsWith('http') ? url : getBaseURL() + url);
235                }
236            } else if (imageTree === 'true') {
237                processImageObject(data.node.id, searchIndex, false);
238            } else {
239                $.getJSON(
240                    contextPath + '/ajax/obj/' + data.node.id + '/' + searchIndex + "?children=" + (parentId !== null),
241                    '', function (response) {
242                        var toObject = null;
243                        if (parentId !== null) {
244                            toObject = tree.find('#' + data.node.id);
245                        }
246                        object.displayObject(response, toObject);
247                    });
248            }
249        }).on("open_node.jstree", function (e, data) {
250            if (customSearchDialog.css('display') === 'block') {
251                customSearchDialog.modal({backdrop:false}).modal('hide');
252            }
253            activate = true;
254            object.printPageList(data);
255            var childrens = data.node.children;
256            setTimeout(() => {
257                childrens.forEach(id => {
258                    const child = tree.jstree(true).get_node(id);
259                    if (!child) return;
260
261                    if (tree.jstree('is_open', '#' + id)) {
262                        object.printPageList(child);
263                    }
264                    else if (child.original && child.original.fullOpen) {
265                        tree.jstree('open_node', '#' + id);
266                    }
267                });
268            }, 50);
269        }).on("close_node.jstree", function (e, data) {
270            const children = data.node.children || [];
271            children.forEach(id => {
272                if (tree.jstree('is_open', '#' + id)) {
273                    tree.jstree('close_node', '#' + id);
274                }
275            });
276        }).on('loaded.jstree', function (e, data) {
277            if (randomImageTree === 'true') {
278                object.printNextImages(data);
279            } else {
280                if (!((objectId === null || objectId === "") && searchByPages === 'true')) {
281                    if(!isTreeOfObject) {
282                        object.getPages(page);
283                    } else {
284                        object.printPageList(data);
285                    }
286                }
287                if (parentId === null) {
288                    //здесь выделяется и активируется первый элемент дерева
289                    if (treeContainer.find('.jstree-anchor').size() > 0) {
290                        if (imageTree !== 'true' || objectId === undefined || objectId === null || objectId==="") {
291                            tree.jstree('select_node', 'ul > li:first-child')
292                                .trigger('activate_node.jstree', {node: {id: tree
293                                    .find('ul > li:first-child').attr('id')}});
294                            if (imageTree === 'true') {
295                                tree.jstree('open_node', '#' + tree
296                                        .find('ul > li:first-child').attr('id'));
297                            }
298                        }
299                    } else {
300                        $('.component-' + componentId).addClass('emptyTree');
301                        if (!(!(objectId === null || objectId === "") && searchByPages === 'true')) {
302                            treeContainer
303                                .find('#tree-' + componentId)
304                                .empty().html("<span class='no-result'>Данные по вашему запросу не были найдены.</span>");
305                        }
306
307                    }
308                    if (selectedObjectType !== null) {
309                        object.selectObjectType(selectedObjectType);
310                    }
311                }
312            }
313            tree.jstree(true).redraw(true);
314
315        });
316    };
317
318    this.printPageList = function printPageList(data) {
319        var pageList, pageListId1, pageListId2, pages = '';
320        var node = data.node !== undefined ? data.node : data;
321        if (node.children !== undefined) {
322            pageListId1 = (node.children)[0];
323            pageListId2 = (node.children)[node.children.length - 1];
324        } else {
325            var pl = $(data.instance.element).find('.pageList');
326            if (pl.length > 0) {
327                pageListId1 = pl[0].id;
328                pageListId2 = pl[1].id;
329            }
330        }
331        if (pageListId1 !== null) {
332            pageList = $('#' + pageListId1 + '.pageList > a');
333            pages = pageList.text();
334        }
335
336        if (pages !== '') {
337            if (paginationTop === undefined || paginationTop === null
338                || paginationTop === '' || paginationTop === "true") {
339                object.displayPageList(pageList.parent(), pages, node.id);
340            } else {
341                object.hidePageList(pageList.parent());
342            }
343            if (paginationBottom === undefined || paginationBottom === null
344                || paginationBottom === '' || paginationBottom === "true") {
345                object.displayPageList($('#' + pageListId2), pages, node.id);
346            } else {
347                object.hidePageList($('#' + pageListId2));
348            }
349        }
350    };
351
352    this.printNextImages = function printNextImages(data) {
353        $('.random-next-images').click(function () {
354            object.initTree(1);
355        });
356    };
357
358    this.selectObjectType = function selectObjectType(objectType) {
359        $(document).on('show.bs.modal', '.custom-search-dialog', centerModal);
360        $('#customSearchTabs a[href="#' + objectType + '"]').tab('show');
361        $('.custom-search-dialog').modal({backdrop:false}).modal('show');
362    };
363
364    /**
365     * получает список страниц от сервера и устанавливает их в верхней и нижней части дерева
366     * @param page - текущая страница
367     * @param ls - размер списка
368     */
369    this.getPages = function getPages(page) {
370        var ls = $.cookie('ls');
371
372        $.ajax({
373            dataType: 'html',
374            url: contextPath + '/ajax/pages/' + searchIndex,
375            data: {
376                page: page,
377                size: ls,
378                parentId: dataParentId,
379                objectType: objectType,
380                count: count,
381                alphabet : alphabet,
382                tabId: tabId
383            },
384            success: function (response) {
385                if (response !== null && response != '') {
386
387                    if (paginationTop == "true") {
388                        object.displayPageList($('#pageListTop-'+componentId), response, null);
389                    }
390                    if (paginationBottom == "true") {
391                        object.displayPageList($('#pageListBottom-'+componentId), response, null);
392                    }
393                } else {
394                    object.hidePageList($('#pageListTop-'+componentId));
395                    object.hidePageList($('#pageListBottom-'+componentId));
396                }
397            }
398        });
399    };
400
401    this.hidePageList = function hidePageList(pageList) {
402        pageList.hide();
403    };
404
405    /**
406     * Прорисовавает страницы на экране.
407     * @param pageList - DOM елемент для прорисовки страниц
408     * @param data - данные по страницам
409     * @param nodeId - id нода
410     */
411    this.displayPageList = function displayPageList(pageList, data, nodeId) {
412        pageList.show();
413        pageList.empty();
414
415        var pageArray = data.split(',');
416        if (pageArray[4] < 2) return;
417
418        if (pageArray.length > 5) {
419            if (pageArray[2] !== 1) {
420                pageList.append(object.getBtn(pageArray[1], '<', pageArray[2] === 1, nodeId));
421            }
422            pageList.append(' ' + pageArray[5] + ' из ' + pageArray[6] + ' ');
423            if (pageArray[2] !== pageArray[4]) {
424                pageList.append(object.getBtn(pageArray[3], '>', pageArray[2] === pageArray[4], nodeId));
425            }
426        } else {
427
428            pageList.append(object.getBtn(pageArray[0], '<<', pageArray[2] === 1, nodeId));
429            pageList.append(object.getBtn(pageArray[1], '<', pageArray[2] === 1, nodeId));
430
431            var inputGroup1 = $('<div class="form-group input-group-xs"><label class="sr-only" for="">Page</label></div>');
432            var pageInput = $('<input type="text" class="form-control page-input">');
433            pageInput.val(pageArray[2]);
434            if (nodeId === undefined || nodeId === null) {
435                pageInput.keyup(function (e) {
436                    if (e.keyCode !== 13) return;
437                    var page = parseInt($(this).val());
438                    var max = $(this).parent().parent().children().filter('button')[3].value;
439                    if (!isNaN(page)) {
440                        if (page < 1) page = 1;
441                        if (page > max) page = max;
442                        object.initTree(page);
443                    }
444                });
445            } else {
446                pageInput.keyup(function (e) {
447                    if (e.keyCode !== 13) return;
448                    var page = parseInt($(this).val());
449                    var max = $(this).parent().parent().children().filter('button')[3].value;
450                    if (!isNaN(page)) {
451                        if (page < 1) page = 1;
452                        if (page > max) page = max;
453                        var nodeObj = $($(this).parents().get(3));
454                        nodePages[nodeObj.attr('id')] = page;
455                        $('#tree-'+componentId).jstree().refresh_node(nodeObj);
456                    }
457                });
458            }
459            pageList.append(inputGroup1);
460            inputGroup1.append(pageInput);
461
462            pageList.append(' из ');
463
464            var inputGroup2 = $('<div class="form-group input-group-xs"><label class="sr-only" for="">Pages</label></div>')
465            var pagesInput = $('<input type="text" id="maxPage" disabled="disabled" class="form-control page-input">');
466            pagesInput.val(pageArray[4]);
467            pageList.append(inputGroup2);
468            inputGroup2.append(pagesInput);
469
470            pageList.append(object.getBtn(pageArray[3], '>', pageArray[2] === pageArray[4], nodeId));
471            pageList.append(object.getBtn(pageArray[4], '>>', pageArray[2] === pageArray[4], nodeId));
472        }
473    };
474
475    /**
476     * Вспомогательный метод для отрисовки кнопок и обработки событий для списка страниц дерева.
477     * @param val - значение кнопки
478     * @param text - текст кнопки
479     * @param isDisabled - отключена кнопка или нет
480     * @param nodeId - id нода
481     * @returns {*|jQuery|HTMLElement}
482     */
483    this.getBtn = function getBtn(val, text, isDisabled, nodeId) {
484        var btn = $('<button type="button" class="btn btn-default btn-xs"></button>');
485        if (isDisabled) btn.addClass("disabled");
486        btn.html(text);
487        btn.val(val);
488
489        if (nodeId === undefined || nodeId === null) {
490            btn.click(function () {
491                var fixedMenuHeight = 0,
492                    fixedMenu = $('.fixedmenu'),
493                    scrollTop = treeContainer.offset().top;
494                if (treeContainer.hasClass('tree-container-children') && fixedMenu.length > 0) {
495                    fixedMenuHeight = fixedMenu.height();
496                }
497                if ($(window).scrollTop() > scrollTop) {
498                    $('html, body').animate({
499                        scrollTop: scrollTop - fixedMenuHeight
500                    }, 500);
501                }
502                object.initTree(parseInt($(this).val()));
503            });
504        } else {
505            btn.click(function () {
506                var nodeObj = $($(this).parents().get(2));
507                nodePages[nodeObj.attr('id')] = $(this).val();
508                $('#tree-'+componentId).jstree().refresh_node(nodeObj);
509            });
510        }
511
512        return btn;
513    };
514
515    /**
516     * Отрисовывает объект
517     * @param object - JSON представление объекта
518     * @param toObject - объект для показа данных
519     */
520    this.displayObject = function displayObject(object, toObject) {
521        var objectDD, i;
522        if (toObject !== null) {
523            objectDD = toObject.find('.objectDD');
524            if (objectDD === null || objectDD.length === 0) {
525                objectDD = $('<div class="objectDD"></div>');
526            } else {
527                objectDD.empty();
528            }
529            objectDD.appendTo(toObject);
530            toObject.find('.jstree-anchor').hide();
531            objectDD.show();
532            objectDD.append($('<div class="closeBtn">X</div>'));
533        } else {
534            objectDD = $("#objectDD-" + componentId).empty();
535
536            if (object.textCount !== 0) {
537                objectDD.addClass('readmore');
538            }
539        }
540
541        var objectTypeName = $('#objectTypeName' + componentId);
542
543        var images = object.images;
544        if (images !== null && images.length > 0) {
545            this.appendImages(object, images, objectDD);
546        }
547
548        var files = object.files;
549        if (files !== null && files.length > 0) {
550            this.appendFiles(object, files, objectDD);
551        }
552
553        var notifications = object.notifications;
554        if (notifications !== null && notifications.length > 0) {
555            this.appendNotifications(object, notifications, objectDD);
556        }
557
558        if (object.linkButtons) {
559            this.appendLinkButtons(object, objectDD);
560        }
561
562        if (object.topTitle && object.title !== null && object.title !== "") {
563            this.appendTitle(object, objectDD);
564        }
565
566        var attributes = object.attributes;
567        if (attributes !== null) {
568            for (i = 0; i < attributes.length; i++) {
569                this.appendAttribute(object, attributes[i], objectDD);
570            }
571        }
572
573        var groups = object.groups;
574        if (groups !== null) {
575            for (i = 0; i < groups.length; i++) {
576                this.appendGroup(object, groups[i], objectDD);
577            }
578        }
579
580        if (object.showPermalink) {
581            this.appendUrl(object, objectDD);
582        }
583
584        this.appendComment(object, objectDD);
585
586        var trees = object.childrenTrees;
587
588        objectDD.parent().find('.children-trees').remove();
589        objectDD.parent().find('.tab-content').remove();
590
591        if (trees !== null && trees.length > 0) {
592            this.appendTrees(searchIndex, object, trees, objectDD);
593        }
594
595        if (!object.showTree) {
596            $('#tree-container-' + componentId).hide();
597            $('#col-resize-' + componentId).hide();
598        }
599
600        objectDD.find('.readmore').readmore({collapsedHeight:object.textCount, moreLink: '<a href="#">Подробнее...</a>', lessLink: '<a href="#">Скрыть...</a>'});
601        //did not work
602        //$(document).find('.sobr-expandable-annotation').readmore({collapsedHeight:object.textCount, moreLink: '<a href="#">Подробнее...</a>', lessLink: '<a href="#">Скрыть...</a>'});
603    };
604
605    this.appendUrl = function appendUrl(object, objectTo) {
606        var dataLine, dataLabel, dataWrap;
607        dataLine = $('<div class="dataLine"></div>');
608        dataLabel = $('<div class="dataLabel"></div>');
609        dataWrap = $('<div class="dataWrap"></div>');
610
611        dataLabel.html('Постоянная ссылка на данное описание:');
612        var link = getBaseURL() + (object.linkPrefix !== null ? object.linkPrefix : '/object/') + object.id;
613        dataWrap.html('<a href="' + link + '" rel="noopener noreferrer" target="_blank">' + link + '</a>');
614
615        objectTo.append(dataLine);
616        dataLine.append(dataLabel);
617        dataLine.append(dataWrap);
618    };
619
620    this.appendComment = function appendUrl(object, objectTo) {
621        if (object.comment !== null) {
622            var dataLine, dataWrap;
623            dataLine = $('<div class="dataLine"></div>');
624            dataWrap = $('<div class="dataWrap dataComment"></div>');
625
626            dataWrap.html(object.comment);
627
628            objectTo.append(dataLine);
629            dataLine.append(dataWrap);
630        }
631
632    };
633
634    this.appendTitle = function (object, objectTo) {
635        var dataLine, dataLabel, dataWrap;
636        dataLine = $('<div class="object-title"></div>');
637
638        // dataLabel.html('Постоянная ссылка на данное описание:');
639        var link = getBaseURL() + (object.linkPrefix !== null ? object.linkPrefix : '/object/') + object.id;
640        dataLine.append('<a href="' + link + '" rel="noopener noreferrer" target="_blank">' + object.title + '</a>');
641
642        objectTo.append(dataLine);
643    };
644
645    /**
646     * Присоединение аттрибута к указанному элементу
647     * @param attribute - аттрибут
648     * @param toObject - элемент
649     */
650    this.appendAttribute = function appendAttribute(object, attribute, toObject, delimiter, showDelimiter) {
651        //не показывать пустые аттрибуты
652        if (attribute.text === null || attribute.text === '') return;
653        var dataLine, dataLabel, dataWrap, aTag;
654        dataLabel = $('<div class="dataLabel"></div>');
655
656        if (delimiter !== undefined && delimiter !== null && delimiter !== "") {
657            dataLine = $('<span class="dataLine"></span>');
658            dataLine.css('width', 'auto');
659            dataWrap = $('<span class="dataWrap"></span>');
660        } else {
661            dataLine = $('<div class="dataLine"></div>');
662            if (attribute.main) {
663                // setMetaKey(attribute.text);
664                dataWrap = $('<h4 class="dataWrap"></h4>');
665            } else {
666                dataWrap = $('<div class="dataWrap"></div>');
667            }
668        }
669
670        dataLine.attr('id', attribute.id);
671        dataLabel.html(attribute.name);
672
673        if(attribute.url !== null && (!attribute.onlyText || attribute.type === 5 || attribute.type === 10)){
674            aTag = $('<a></a>');
675            //обработка ссылки на видео
676            if (attribute.url.indexOf('mp4') === -1 && attribute.url.indexOf('flv') === -1 && attribute.url.indexOf('mp3') === -1 && attribute.url.indexOf('wma') === -1 && attribute.url.indexOf('wav') === -1) {
677                if (attribute.type === 5) {
678                    aTag = $('<a data-lightbox="'+ attribute.id +'" data-title="' + attribute.text +'"></a>');
679                    var img = $("<img/>");
680                    img.attr('src', getBaseURL() + attribute.url);
681                    img.attr('title', attribute.text);
682                    aTag.attr('href', getBaseURL() + attribute.url.replace('size=1','size=3'));
683                    img.appendTo(aTag);
684                } else  {
685                    aTag.attr('href', getBaseURL() + attribute.url);
686                    if (showDelimiter && delimiter !== undefined && delimiter !== null) {
687                        aTag.html(attribute.text + delimiter);
688                    } else {
689                        aTag.html(attribute.text);
690                    }
691                }
692
693            } else if (attribute.url.indexOf('mp4') === -1 && attribute.url.indexOf('flv') === -1) {
694                aTag = buildAudioTag(attribute.url);
695            } else{
696                aTag = buildVideoTag(attribute.url);
697            }
698
699            aTag.attr('target', "_blank");
700            dataWrap.append(aTag);
701        } else if (attribute.dictionary !== null && !attribute.onlyText) {
702            aTag = $('<a></a>');
703            aTag.attr('href', getBaseURL() + (attribute.linkPrefix !== null ? attribute.linkPrefix :
704                    (object.linkPrefix !== null ? object.linkPrefix : '/object/')) + attribute.dictionary +
705                (attribute.linkSuffix !== null ? attribute.linkSuffix : (object.linkSuffix !== null ? object.linkSuffix : '')));
706            if (showDelimiter && delimiter !== undefined && delimiter !== null) {
707                aTag.html(attribute.text + delimiter);
708            } else {
709                aTag.html(attribute.text);
710            }
711            dataWrap.html(aTag);
712        } else {
713            if (showDelimiter && delimiter !== undefined && delimiter !== null) {
714                dataWrap.html(attribute.text + delimiter);
715            } else {
716                dataWrap.html(attribute.text);
717            }
718        }
719
720        toObject.append(dataLine);
721        if (attribute.showName) {
722            dataLine.append(dataLabel);
723        }
724        dataLine.append(dataWrap);
725    };
726
727    /**
728     * Присоединение группы к указанному элементу
729     * @param group - группа
730     * @param toObject - элемент
731     */
732    this.appendGroup = function appendGroup(object, group, toObject) {
733        //не показывать пустые группы аттрибутов
734        if(group.groupRecords === null || group.groupRecords.length === 0) return;
735        var show = false, i;
736        for (i = 0; i < group.groupRecords.length; i++) {
737            var groupRecord = group.groupRecords[i];
738            for (var j = 0; j < groupRecord.attributes.length; j++) {
739                var attribute = groupRecord.attributes[j];
740                if (!attribute.empty) {
741                    show = true;
742                    break;
743                }
744            }
745            if (show) {
746                break;
747            }
748        }
749        if (!show) {
750            return;
751        }
752        var dataLine, dataLabel;
753        dataLine = $('<div class="dataLine"></div>');
754        dataLabel = $('<div class="dataLabel dataLabelGroup"></div>');
755
756        dataLine.attr('id', group.id);
757        dataLabel.html(group.name);
758
759        if (group.showGroupName) {
760            toObject.append(dataLine);
761        }
762
763
764        var groupRecords = group.groupRecords;
765        var groupDiv = $('<div class="group"></div>').appendTo(toObject);
766        for (i = 0; i < groupRecords.length; i++) {
767            this.appendGroupRecord(object, groupRecords[i], groupDiv, group.delimiter, i !== groupRecords.length - 1);
768            if (!(group.delimiter !== undefined && group.delimiter !== null && group.delimiter !== "")) {
769                groupDiv.append("<hr>");
770            }
771        }
772
773        dataLine.append(dataLabel);
774        dataLine.append("<hr>");
775    };
776
777    /**
778     * Присоединение групповой записи к указанному элементу
779     * @param groupRecord - групповая запись
780     * @param toObject - элемент
781     */
782    this.appendGroupRecord = function appendGroupRecord(object, groupRecord, toObject, delimiter, showDelimiter) {
783        var attributes = groupRecord.attributes;
784        for (var i = 0; i < attributes.length; i++) {
785            var show = showDelimiter || !this.isLastNotEmpty(attributes, i);
786            this.appendAttribute(object, attributes[i], toObject, delimiter, show);
787        }
788    };
789
790    this.isLastNotEmpty = function isLastNotEmpty(attributes, i) {
791        for (var j = i + 1; j < attributes.length; j++) {
792            var attribute = attributes[j];
793            if (attribute.text !== null && attribute.text !== '') {
794                return false;
795            }
796        }
797        return true;
798    };
799
800    this.appendLinkButtons = function appendLinkButtons(object, objectTo) {
801        var dataLine, aTag, divTag, toolbar;
802        dataLine = $('<div class="buttonView"></div>');
803        toolbar = $('<div class="btn-toolbar" role="toolbar"></div>');
804        var buttons = object.linkButtons.split(",");
805        for (var i = 0; i < buttons.length; i++) {
806            var button = buttons[i];
807            var params = button.split(";");
808
809            divTag = $('<div class="btn-group" role="group" style="margin-bottom: 5px;"></div>');
810
811            aTag = $('<a class="btn btn-default" rel="noopener noreferrer" target="_blank"></a>');
812
813            aTag.attr('href', params[1].indexOf('http') !== -1 ? params[1] : getBaseURL() + params[1]);
814            aTag.html(params[0]);
815
816            divTag.append(aTag);
817            toolbar.append(divTag);
818        }
819
820        dataLine.append(toolbar);
821        objectTo.append(dataLine);
822    };
823
824    this.appendImages = function appendImages(object, images, toObject) {
825        var imageView, container, inner;
826
827        imageView = $('<div></div>');
828        imageView.addClass('imageView');
829        toObject.append(imageView);
830
831        container = $('<div></div>');
832        container.attr('id', 'imageView-' + object.id);
833        container.addClass('carousel');
834        container.addClass('slide');
835        container.data('ride','carousel');
836        imageView.append(container);
837
838        inner = $('<div></div>');
839        inner.addClass('carousel-inner');
840        if (images.length > 0 && !(images[0].path !== null && images[0].path.indexOf('imageViewer/img') !== -1)) {
841            inner.addClass('lightGallery');
842        }
843        inner.attr('role','listbox');
844        container.append(inner);
845
846        for (var i = 0; i < images.length; i++) {
847            var image = images[i];
848
849            var item = $('<div></div>');
850            item.addClass('item');
851            if (i === 0) {
852                item.addClass('active');
853            }
854            inner.append(item);
855
856            var a;
857            if (image.path !== null && image.path.indexOf('imageViewer/img') !== -1) {
858                a = $('<a></a>');
859                a.attr('href', getBaseURL() + image.path);
860                a.attr('target', '_blank');
861            } else {
862                a = $('<a data-lightbox="' + object.id + '" data-title="' + image.title + '"></a>');
863                a.attr('data-src', getBaseURL() + image.url);
864                a.attr('href', getBaseURL() + image.url);
865                a.attr('data-sub-html', image.title);
866            }
867
868            item.append(a);
869
870            var img = $('<img/>');
871            img.attr('src', getBaseURL() + image.url.replace("size=3","size=1"));
872            img.attr('title', image.title);
873            a.append(img);
874        }
875
876        if (images.length > 1) {
877            container.append($('<a class="left carousel-control" href="#imageView-'+ object.id +'" role="button" data-slide="prev">' +
878                '<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span><span class="sr-only">Previous</span></a>' +
879                '<a class="right carousel-control" href="#imageView-'+ object.id +'" role="button" data-slide="next">' +
880                '<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span><span class="sr-only">Next</span></a>'));
881        }
882
883        preparedLightGallery();
884    };
885
886    this.appendFiles = function appendFiles(object, files, toObject) {
887        var fileView = $('<div id=\"fileView\" class=\"fileView\"></div>').prependTo(toObject);
888
889        for (var i = 0; i < files.length; i++) {
890            var div = $('<div></div>'),
891                file = files[i],
892                text = file.title,
893                aTag;
894
895            if (file.url.indexOf('.mp4') === -1 && file.url.indexOf('.avi') === -1 && file.url.indexOf('.vob') === -1 && file.url.indexOf('mp3') === -1 && file.url.indexOf('wma') === -1 && file.url.indexOf('wav') === -1) {
896                var src = getBaseURL() + '/static/images/attFile.png';
897                if (file.url.indexOf('.pdf') !== -1 || file.url.indexOf('imageViewer') !== -1) {
898                    src = getBaseURL() + '/static/images/pdf.png';
899                } else if (file.url.indexOf('.doc') !== -1) {
900                    src = getBaseURL() + '/static/images/doc.png';
901                }
902
903                aTag = '<a href=\"' + getBaseURL() + file.url + '\" rel="noopener noreferrer" target="_blank" title="' + text + '"><img src="' + src + '" /></a>';
904                $(aTag).appendTo(div);
905            } else if (file.url.indexOf('mp4') === -1 && file.url.indexOf('avi') === -1 && file.url.indexOf('.vob') === -1){
906                aTag = buildAudioTag(getBaseURL() + file.url);
907                aTag.appendTo(div);
908            }else{
909                aTag = buildVideoTag(getBaseURL() + file.url);
910                aTag.appendTo(div);
911            }
912
913            div.appendTo(fileView);
914        }
915    };
916
917    this.appendNotifications = function appendNotifications(object, notifications, toObject) {
918        var notificationView = $('<div id=\"notificationView\" class=\"notificationView\"></div>').prependTo(toObject);
919
920        for (var i = 0; i < notifications.length; i++) {
921            var div = $('<div class="notificationViewContainer"></div>'),
922                notification = notifications[i];
923
924            if (notification.title !== null) {
925                $('<div>' + notification.title + ':' + '</div>').appendTo(div);
926            }
927            $('<div>' + notification.text + '</div>').appendTo(div);
928
929            div.appendTo(notificationView);
930        }
931    };
932
933    this.appendTrees = function appendTrees(searchIndex, object, trees, toObject) {
934        var container, tabs, tabContent, i;
935
936        var treeContainer = toObject.parents('.data-container').find('.tree-container').first();
937
938        container = $('<div class="children-trees"></div>');
939        tabs = $('<ul class="nav nav-tabs" role="tablist"></ul>');
940        container.append(tabs);
941
942        tabContent = $('<div class="tab-content"></div>');
943
944        for (i = 0; i< trees.length; i++) {
945            var tab = $('<li role="presentation"></li>');
946
947            tab.appendTo(tabs);
948
949            var a = $('<a href="#'+ trees[i].systemName +'" aria-controls="'+ trees[i].systemName +'" role="tab" data-toggle="tab"></a>');
950            a.html(trees[i].name);
951            a.appendTo(tab);
952
953            var content = $('<div role="tabpanel" class="tab-pane" id="'+trees[i].systemName+'"></div>');
954            if (i === 0) {
955                tab.addClass("active");
956                content.addClass("active");
957            }
958
959            var tree = $('<div id="tree-container-' + trees[i].id + '" class="tree-container tree-container-children">' +
960                '<div id="tree-' + trees[i].id + '"></div>');
961            tree.attr('data-paging-top', treeContainer.attr('data-paging-top'));
962            tree.attr('data-paging-bottom', treeContainer.attr('data-paging-bottom'));
963
964            tree.appendTo(content);
965
966            content.appendTo(tabContent);
967        }
968
969        container.appendTo(toObject.parent());
970        tabContent.appendTo(toObject.parent());
971
972        for (i=0; i < trees.length; i++) {
973            new Tree(trees[i].id, searchIndex, 1, object.id, trees[i].id, null);
974        }
975    };
976
977    this.initTree(page);
978}
979
980function setMetaKey(text) {
981    if (text !== '') {
982        $('title').html(title + " - " + text);
983        $('meta[name="description"]').attr('content', text);
984        $('meta[name="keywords"]').attr('content', text);
985    } else {
986        $('title').html(title);
987        $('meta[name="description"]').attr('content','');
988        $('meta[name="keywords"]').attr('content','');
989    }
990}
991
992function setAlphabet(btn) {
993    var alphabet = btn.parents('.alphabet').first(),
994        treeContainer = $('#tree-container-' + alphabet.attr('data-component-id')).first();
995    alphabet.find('.tree-letter').removeClass('active');
996    if (btn.hasClass('letter-clear-filter')) {
997        treeContainer.attr('data-alphabet', '');
998    } else {
999        btn.addClass('active');
1000        treeContainer.attr('data-alphabet', btn.find('span').html());
1001    }
1002    alphabet.dialog('close');
1003
1004    initTreeFromNode(treeContainer);
1005}
1006
1007/**
1008 * Переключение режимов дерева
1009 * @param button
1010 */
1011function changeTreeMode(button) {
1012    var treeContainer = button.parents('.component-tree').first();
1013    button.parent().children().removeClass('active');
1014    button.addClass('active');
1015    if (button.hasClass('table-mode-button')) {
1016        while (treeContainer.hasClass('list-mode')) {
1017            treeContainer.removeClass('list-mode');
1018        }
1019        while (!treeContainer.hasClass('table-mode')) {
1020            treeContainer.addClass('table-mode');
1021        }
1022    } else {
1023        while (treeContainer.hasClass('table-mode')) {
1024            treeContainer.removeClass('table-mode');
1025        }
1026        while (!treeContainer.hasClass('list-mode')) {
1027            treeContainer.addClass('list-mode');
1028        }
1029    }
1030}
1031
1032function initTreeFromNode(node) {
1033    var selectedObjectType = node.attr('data-selected-objecttypes');
1034    var imageTree = node.attr('data-component-image-tree');
1035    var objectType = node.attr('data-objecttype');
1036    if (objectType == "") {
1037        objectType = null;
1038    }
1039    var tree = new Tree(node.attr('data-component-id'), node.attr('data-search-index'), 1, null, objectType,
1040        selectedObjectType != '' ? selectedObjectType : null, imageTree);
1041}
1042
1043function changeSort(elem) {
1044    var me = $(elem);
1045
1046    var treeContainer = me.parents('.tree-container').first();
1047    var componentId = treeContainer.attr('data-component-id');
1048    var searchIndex = treeContainer.attr('data-search-index');
1049    var selectedObjectType = treeContainer.attr('data-selected-objecttypes');
1050    var imageTree = treeContainer.attr('data-component-image-tree');
1051
1052    if (me.hasClass('sort-date')) {
1053        if (me.parent().find('.sort-condition-date').hasClass('sort-condition-asc')) {
1054            treeContainer.attr('data-sort-condition-number', -1);
1055        } else {
1056            treeContainer.attr('data-sort-condition-number', 1);
1057        }
1058    } else {
1059        treeContainer.attr('data-sort-condition-number', 0);
1060    }
1061
1062    initTree(componentId, searchIndex, 1, null, null, selectedObjectType !== '' ? selectedObjectType : null, imageTree);
1063}
1064
1065
1066function setIndexAlphabet(btn) {
1067    var filterTitle = $('.index-filter-title-container');
1068    filterTitle.text("");
1069
1070    //Стираем предыдущее значение в поле текста
1071    $('.indexFilterInput').val("");
1072
1073    var alphabet = btn.parents('.alphabet').first();
1074    //Убираем с предыдущей активной буквы
1075    alphabet.find('.tree-letter-index').removeClass('active');
1076
1077    if (btn.hasClass('letter-clear-filter')) {
1078        //снятие фильтрации
1079        alphabet.dialog('close');
1080        //Показываем все
1081        $('.jstree-container-ul').children('li').each(function() { $(this).show() });
1082
1083        searchByIndexWordValue = null;
1084        searchByIndexLetterValue = null;
1085
1086        initTreeByIndexSearch();
1087    } else {
1088        btn.addClass('active');
1089        alphabet.dialog('close');
1090        var letter = btn.find('span').html();
1091        //Ставим на место предыдущей фильтрации
1092        filterTitle.text("Фильтрация по начальной букве/цифре: " + letter.toUpperCase() + ((new RegExp("[A-Z]")).test(letter.toUpperCase()) ? " (лат.)" : ""));
1093        filterIndexByAlphabet(letter);
1094    }
1095}
1096
1097function filterIndexByAlphabet(letter) {
1098
1099    searchByIndexWordValue = null;
1100    searchByIndexLetterValue = letter;
1101
1102    initTreeByIndexSearch();
1103}
1104
1105function setIndexInputSearch(word) {
1106    var targetContainer = $('.jstree-container-ul');
1107    //снятие активного состояния с дерева
1108    $('.tree-letter-index').removeClass('active');
1109
1110    var filterTitle = $('.index-filter-title-container');
1111    filterTitle.text("");
1112
1113    if(word === null || word === '') {
1114    } else {
1115        filterTitle.text("Фильтрация по тексту в указателе: " + word);
1116    }
1117    targetContainer.show();
1118
1119    searchByIndexWordValue = word;
1120    searchByIndexLetterValue = null;
1121
1122    initTreeByIndexSearch();
1123}
1124
1125function initTreeByIndexSearch() {
1126    $('.tree-container').each(function() {
1127        var me = $(this),
1128            showTree = me.attr('data-show-tree');
1129        if (showTree === 'true') {
1130            initTreeFromNode($(this));
1131        }
1132    });
1133}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.