<?xml version="1.0" encoding="UTF-8" standalone="no"?><addon xmlns="http://icplayer.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Hierarchical_Table_Of_Contents" xsi:schemaLocation="http://icplayer.com ../../tools/addon.xsd">
    <model>
        <property displayName="Title label" isLocalized="true" name="titleLabel" nameLabel="Hierarchical_Table_Of_Contents_property_title_label" type="string"/>
        <property displayName="Display only chapters" name="displayOnlyChapters" nameLabel="Hierarchical_Table_Of_Contents_property_display_only_chapters" type="boolean"/>
        <property displayName="Depth of expand" name="expandDepth" nameLabel="Hierarchical_Table_Of_Contents_property_expand_depth" type="string"/>
        <property displayName="Show Pages" isLocalized="true" name="showPages" nameLabel="Hierarchical_Table_Of_Contents_property_show_pages" type="{All, Reportable, Not-reportable}"/>
        <property displayName="Lang attribute" name="langAttribute" nameLabel="Hierarchical_Table_Of_Contents_property_lang_attribute" type="string"/>
        <property displayName="Speech texts" name="speechTexts" nameLabel="Hierarchical_Table_Of_Contents_property_speech_texts" type="staticlist">
            <property name="Title" nameLabel="Hierarchical_Table_Of_Contents_speech_text_title" type="staticrow">
                <property name="Title" nameLabel="Hierarchical_Table_Of_Contents_speech_text_title" type="string"/>
            </property>
            <property name="GoToPage" nameLabel="Hierarchical_Table_Of_Contents_speech_text_go_to_page" type="staticrow">
                <property name="GoToPage" nameLabel="Hierarchical_Table_Of_Contents_speech_text_go_to_page" type="string"/>
            </property>
            <property name="Chapter" nameLabel="Hierarchical_Table_Of_Contents_speech_text_chapter" type="staticrow">
                <property name="Chapter" nameLabel="Hierarchical_Table_Of_Contents_speech_text_chapter" type="string"/>
            </property>
            <property name="Expanded" nameLabel="Hierarchical_Table_Of_Contents_speech_text_expanded" type="staticrow">
                <property name="Expanded" nameLabel="Hierarchical_Table_Of_Contents_speech_text_expanded" type="string"/>
            </property>
            <property name="Collapsed" nameLabel="Hierarchical_Table_Of_Contents_speech_text_collapsed" type="staticrow">
                <property name="Collapsed" nameLabel="Hierarchical_Table_Of_Contents_speech_text_collapsed" type="string"/>
            </property>
        </property>
    </model>
<css>.hier_report {
    padding: 15px;
    border-radius: 5px;
    border: 1px solid gray;
    background-color: white;
    color: gray;
    overflow: auto;
}

.hier_report td{
    padding: 10px;
}

.hier_report-header{
    font-weight: bold;
    color: black !important;
    background-color: #bde0ff;
}
.hier_report-footer{
    font-weight: bold;
    color: black !important;
    background-color: #bde0ff;
}

.hier_report-chapter{
    background-color: Lavender;
}

.hier_report-odd{
    background-color: AliceBlue;
}

.hier_report-even{
    background-color: #f0f1ff;
}

.hier_report-progress {
    text-align:center;
    color:#0A8DBD;
    display: inline-block;
    width: 190px;
}

.hier_report-checks {
    width: 10%;
    color: green;
    text-align: center;
}

.hier_report-mistakes {
    width: 10%;
    color: #990000;
    text-align: center;
}

.hier_report-errors {
    width: 10%;
    color: red;
    text-align: center;
}

.hier_report-page-score {
    width: 10%;
    color: blue;
    text-align: center;
}

.hier_report-page-non-max-score, .hier_report-page-max-score {
    width: 10%;
    text-align: center;
}

.ui-progressbar {
    padding:2px;
    width:	130px  !important;
    height: 15px    !important;
    border-radius: 5px;
    border:2px solid #02789F;
    background-color: #3CC6CD;
    border-radius: 5px;
    float: left;
}

.hier_drag-source{
    border: 1px solid orange;
}

.hier_report .treegrid-expander {
	float: left;
}

.hier_report .treegrid-indent {
	float: left;
}

.hier_report .text-wrapper {
	overflow: hidden;
}
</css><view> &lt;div class="hier_report"&gt;
     &lt;table  style="width: 100%"&gt;
     &lt;/table&gt;
 &lt;/div&gt;

</view><preview>&lt;div class="hier_report"&gt;
    &lt;table  style="width: 100%"&gt;
    &lt;/table&gt;
&lt;/div&gt;
</preview><presenter>function AddonHierarchical_Table_Of_Contents_create() {
    var presenter = function () {};
    var presentationController;
    var pageIndex = 0;

    presenter.isVisible = null;
    presenter.keyboardControllerObject = null;

    presenter.ERROR_MESSAGES = {
        EXPAND_DEPTH_NOT_NUMERIC: "Depth of expand is not proper",
    };

    presenter.CSS_CLASSES = {
        TABLE: "table",
        TITLE: "hier_report-header",
        FOOTER: "hier_report-footer",
        TABLE_CONTAINER: "hier_report",
        CHAPTER: "hier_report-chapter",
        CHAPTER_EXPANDER: "treegrid-expander",
        CHAPTER_EXPANDER_EXPANDED: "treegrid-expander-expanded",
        CHAPTER_EXPANDER_COLLAPSED: "treegrid-expander-collapsed",
        CURRENT_PAGE: "current-page",
    };

    presenter.DEFAULT_TTS_PHRASES = {
        Title: "Title",
        GoToPage: "Go to page",
        Chapter: "Chapter",
        Collapsed: "Collapsed",
        Expanded: "Expanded",
    };

    presenter.isFirstEnter = true;

    function returnErrorObject(ec) { return { isValid: false, errorCode: ec }; }

    function returnCorrectObject(v) { return { isValid: true, value: v }; }

    presenter.executeCommand = function (name, params) {
        var commands = {
            'show': presenter.show,
            'hide': presenter.hide
        };

        return Commands.dispatch(commands, name, params, presenter);
    };

    presenter.showErrorMessage = function (message, substitutions) {
        var errorContainer;
        if (typeof(substitutions) == 'undefined') {
            errorContainer = '&lt;p&gt;' + message + '&lt;/p&gt;';
        } else {
            var messageSubst = message;
            for (var key in substitutions) {
                if (substitutions.hasOwnProperty(key)) {
                    messageSubst = messageSubst.replace('%' + key + '%', substitutions[key]);
                }
            }
            errorContainer = '&lt;p&gt;' + messageSubst + '&lt;/p&gt;';
        }
        presenter.$view.html(errorContainer);
    };

    presenter.setPlayerController = function (controller) {
        presentationController = controller;
    };

    presenter.run = function (view, model) {
        presenter.initialize(view, model, false);
    };

    presenter.createPreview = function (view, model) {
        presenter.initialize(view, model, true);
    };

    function addHeader() {
        var headerHTML = "&lt;td&gt; " + presenter.configuration.labels.title + "&lt;/td&gt;";
        $("&lt;tr&gt;&lt;/tr&gt;").prependTo(getJqueryTable()).addClass("hier_report-header").html(headerHTML);
    }

    function addFooter() {
        var row = document.createElement('tr');
        $(row).appendTo(getJqueryTable());
        $(row).addClass("hier_report-footer");
    }

    function createRow(index, parentIndex, isChapter) {
        var row = document.createElement('tr');

        $(row).appendTo(getJqueryTable());
        $(row).addClass("treegrid-" + index);

        if (parentIndex != null) {
            $(row).addClass("treegrid-parent-" + parentIndex);
        }

        if (isChapter) {
            $(row).addClass("hier_report-chapter");
        } else {
            $(row).addClass(index % 2 &gt; 0 ? "hier_report-odd" : "hier_report-even");
        }

        return row;
    }

    function createRowCell(text, isChapter, pageId) {
        const rowCell = document.createElement('td');

        const textWrapper = document.createElement('div');
        textWrapper.classList.add('text-wrapper');
        if (isChapter) {
            textWrapper.textContent = text;
        } else {
            const link = document.createElement('a');
            link.textContent = text;
            link.setAttribute('href', '#');
            link.setAttribute('data-page-id', pageId);

            textWrapper.appendChild(link);
            if (!presenter.isPreview){
                const presentation = presentationController.getPresentation();
                const currentPageId = presentation.getPage(presentationController.getCurrentPageIndex()).getId();

                if (currentPageId === pageId) {
                    link.classList.add(presenter.CSS_CLASSES.CURRENT_PAGE);
                }
            }
        }
        rowCell.append(textWrapper);

        return rowCell;
    }

    function addRow(name, index, parentIndex, isChapter, pageId) {
        const row = createRow(index, parentIndex, isChapter);
        const cell = createRowCell(name, isChapter, pageId);
        row.append(cell);
    }

    function resetScore() {
        return {
            score: 0,
            countedScore: 0,
            maxScore: 0,
            countedMaxScore: 0,
            errorCount: 0,
            checkCount: 0,
            mistakeCount: 0,
            count: 0
        };
    }

    presenter.createPreviewTree = function() {
        var pagesMockup = [
            {name : "Page1", parent : null},
            {name : "Unit1", parent : null},
            {name : "Chapter2", parent : 1},
            {name : "Page5", parent : 6},
            {name : "Page6", parent : 1},
            {name : "Page7", parent : null},
            {name : "Page8", parent : null},
            {name : "Page9", parent : null},
            {name : "Page10", parent : null},
            {name : "Page11", parent : null},
            {name : "Unit2", parent : null},
            {name : "Page12", parent : 10},
            {name : "Page13", parent : 10}
        ];

        var chapterScore = resetScore();
        for (var i = 0; i &lt; pagesMockup.length; i++) {
            if(pagesMockup[i].name == "Unit1" || pagesMockup[i].name == "Unit2"){
                addRow(pagesMockup[i].name, i, pagesMockup[i].parent, true, "some_id");
            }else{
                addRow(pagesMockup[i].name, i, pagesMockup[i].parent, false, "some_id");
            }
        }
        return chapterScore;
    };

    presenter.createTree = function (root, parentIndex, pageCount) {
        var chapterIndex = 0,
            chapterScore = resetScore(),
            pageScore = resetScore(),
            isEmpty = true,
            values = {},
            isEnabled = true;

        for (var i = 0; i &lt; pageCount; i++) {
            var isChapter = (root.get(i).type == "chapter");

            if (!isChapter &amp;&amp; !root.get(i).isReportable() &amp;&amp; presenter.configuration.showPages == "Reportable") continue;
            if (!isChapter &amp;&amp; root.get(i).isReportable() &amp;&amp; presenter.configuration.showPages == "Not-reportable") continue;
            if (!isChapter &amp;&amp; root.get(i).isReportable()) {
                isEmpty = false;
            }
            var pageId = "chapter";
            if (!isChapter) {
                pageId = root.get(i).getId();
            }
            addRow(root.get(i).getName(), pageIndex, parentIndex, isChapter, pageId);
            pageScore = presentationController.getScore().getPageScoreById(pageId);
            pageScore.count = 1;
            pageIndex++;
            if (isChapter) {
                chapterIndex = pageIndex - 1;
                values = presenter.createTree(root.get(i), chapterIndex, root.get(i).size());
                pageScore =  values.pagesScore;
            }
        }

        return { pagesScore: chapterScore, isEmpty: isEmpty };
    };

    function handleMouseClickActions() {
        var commander = presentationController.getCommands(),
            $report = presenter.$view.find('.hier_report tr');

        $report.find('td a').each(function () {
            $(this).click(function (event) {
                event.preventDefault();
                event.stopPropagation();
                commander.gotoPageId($(this).attr('data-page-id'));
            });
        });

        $report.find(`.${presenter.CSS_CLASSES.CHAPTER_EXPANDER}`).each(function () {
            $(this).click(function (event) {
                event.preventDefault();
                event.stopPropagation();
            });
        });
    }

    function expandTree(level) {
        presenter.$view.find('.hier_report table').find('tr').not('.hier_report-header').not('.hier_report-footer').each(function () {
            if ($(this).treegrid('getDepth') &lt; level) {
                $(this).treegrid('expand'); 
            }
        });
    }

    function saveTreeState() {
        var state = [];
        $('.hier_report table').find('tr').not('.hier_report-header').not('.hier_report-footer').each(function () {
            state.push($(this).treegrid('isExpanded'))
        });
        return state;
    }

    function restoreTreeState(state) {
        $('.hier_report table').find('tr').not('.hier_report-header').not('.hier_report-footer').each(function () {
            $(this).treegrid(state[$(this).treegrid('getNodeId')] ? 'expand' : 'collapse');
        });
    }

    presenter.getState = function () {
        return JSON.stringify({
            'treeState': saveTreeState(),
            'isVisible': presenter.isVisible,
        });
    };

    presenter.setState = function (stateString) {
        var state = JSON.parse(stateString);

        restoreTreeState(state.treeState);

        presenter.setVisibility(state.isVisible);
    };

    presenter.validateModel = function (model) {
        var expandDepth = returnCorrectObject(0);
        if (model['expandDepth'].length &gt; 0) {
            expandDepth = ModelValidationUtils.validateInteger(model['expandDepth']);
            if (!expandDepth.isValid) {
                return returnErrorObject('EXPAND_DEPTH_NOT_NUMERIC');
            }
        }
        return {
            ID: model.ID,
            isValid: true,
            width: parseInt(model["Width"], 10),
            height: parseInt(model["Height"], 10),
            isVisible: ModelValidationUtils.validateBoolean(model["Is Visible"]),
            labels: {
                title: model['titleLabel']
            },
            displayOnlyChapters: ModelValidationUtils.validateBoolean(model.displayOnlyChapters),
            expandDepth: expandDepth.value,
            showPages: model.showPages,
            langTag: model.langAttribute,
        };
    };

    presenter.setVisibility = function (isVisible) {
        presenter.$view.css("visibility", isVisible ? "visible" : "hidden");
        presenter.isVisible = isVisible;
    };

    presenter.show = function () {
        if (!presenter.isVisible) {
            presenter.setVisibility(true);
        }
    };

    presenter.hide = function () {
        if (presenter.isVisible) {
            presenter.setVisibility(false);
        }
    };

    presenter.reset = function () {
        presenter.setVisibility(presenter.configuration.isVisible);
    };

    presenter.initialize = function (view, model, isPreview) {
        const upgradedModel = presenter.upgradeModel(model);

        presenter.configuration = presenter.validateModel(upgradedModel);
        if (!presenter.configuration.isValid) {
            presenter.showErrorMessage(presenter.ERROR_MESSAGES[presenter.configuration.errorCode]);
            return;
        }

        presenter.$view = $(view);
        presenter.isPreview = isPreview;
        presenter.lessonScore = {
            pageCount: 0,
            checks: 0,
            errors: 0,
            mistakes: 0,
            score: 0,
            maxScore: 0,
            scaledScore: 0
        };

        $('.hier_report').attr("style", "height: " + presenter.configuration.height + "px");
        presenter.treeID = presenter.configuration.ID + (isPreview ? "Preview" : "");
        presenter.$view.find("div").first().attr('id', presenter.treeID);

        presenter.setVisibility(presenter.configuration.isVisible || isPreview);


        addHeader();
        if (isPreview) {
            presenter.createPreviewTree();
        } else {
            var presentation = presentationController.getPresentation();
            presenter.createTree(presentation.getTableOfContents(), null, presentation.getTableOfContents().size());
            checkIfChapterHasChildren(false);
            if(presenter.configuration.displayOnlyChapters){
                displayOnlyChapters();
            }
        }

        if (presenter.configuration.showTotal) {
            addFooter();
        }

        getJqueryTable().not('.hier_report-header').not('.hier_report-footer').treegrid({
            'initialState': 'collapsed',
            'expanderTemplate': '&lt;div class="treegrid-expander"&gt;&lt;/div&gt;'
        });

        expandTree(presenter.configuration.expandDepth);
        if (!isPreview) {
            handleMouseClickActions();
        }

        if(presenter.configuration.displayOnlyChapters){
            presenter.$view.find("tr").each(function () {
                if($(this).hasClass("hier_report-even") || $(this).hasClass("hier_report-odd")){
                    $(this).remove();
                }
            });
        }

        checkIfChapterHasChildren(true);

        presenter.setSpeechTexts(upgradedModel["speechTexts"]);
        presenter.buildKeyboardController();
    };

    presenter.upgradeModel = function (model) {
        const upgradedLangTagModel = presenter.upgradeLangTag(model);
        const upgradedSpeechTextsModel = presenter.upgradeSpeechTexts(upgradedLangTagModel);
        const upgradedDepthOfExpandModel = presenter.upgradeDepthOfExpand(upgradedSpeechTextsModel);

        return upgradedDepthOfExpandModel;
    };

    presenter.upgradeLangTag = function (model) {
        const upgradedModel = {};
        jQuery.extend(true, upgradedModel, model); // Deep copy of model object

        if (upgradedModel["langAttribute"] === undefined) {
            upgradedModel["langAttribute"] =  '';
        }

        return upgradedModel;
    };

    presenter.upgradeSpeechTexts = function (model) {
        const upgradedModel = {};
        jQuery.extend(true, upgradedModel, model); // Deep copy of model object

        if (!upgradedModel["speechTexts"]) upgradedModel["speechTexts"] = {};

        const modelSpeechTexts = upgradedModel["speechTexts"];

        if (!modelSpeechTexts["Title"]) modelSpeechTexts["Title"] = {Title: ""};
        if (!modelSpeechTexts["GoToPage"]) modelSpeechTexts["GoToPage"] = {GoToPage: ""};
        if (!modelSpeechTexts["Chapter"]) modelSpeechTexts["Chapter"] = {Chapter: ""};
        if (!modelSpeechTexts["Expanded"]) modelSpeechTexts["Expanded"] = {Expanded: ""};
        if (!modelSpeechTexts["Collapsed"]) modelSpeechTexts["Collapsed"] = {Collapsed: ""};

        return upgradedModel;
    };

    presenter.upgradeDepthOfExpand = function (model) {
        const upgradedModel = {};
        jQuery.extend(true, upgradedModel, model); // Deep copy of model object

        if (upgradedModel["expandDepth"] === undefined) {
            upgradedModel["expandDepth"] = '';
        }

        return upgradedModel;
    };

    presenter.setSpeechTexts = function(speechTexts) {
        presenter.speechTexts = {
            ...presenter.DEFAULT_TTS_PHRASES
        };

        if (!speechTexts || $.isEmptyObject(speechTexts)) {
            return;
        }

        presenter.speechTexts = {
            Title: TTSUtils.getSpeechTextProperty(
                speechTexts.Title.Title,
                presenter.speechTexts.Title),
            GoToPage: TTSUtils.getSpeechTextProperty(
                speechTexts.GoToPage.GoToPage,
                presenter.speechTexts.GoToPage),
            Chapter: TTSUtils.getSpeechTextProperty(
                speechTexts.Chapter.Chapter,
                presenter.speechTexts.Chapter),
            Expanded: TTSUtils.getSpeechTextProperty(
                speechTexts.Expanded.Expanded,
                presenter.speechTexts.Expanded),
            Collapsed: TTSUtils.getSpeechTextProperty(
                speechTexts.Collapsed.Collapsed,
                presenter.speechTexts.Collapsed)
        };
    };

    function displayOnlyChapters() {
        presenter.$view.find(".hier_report-chapter").each(function () {
            var element = $(this);
            element.find(".text-wrapper").wrap('&lt;a href=""&gt;&lt;/a&gt;');
            if(element.next('tr[class*=treegrid-parent]').length &gt; 0){
                var dataPageId = element.next().find("a").attr("data-page-id");
                element.find("a").attr("data-page-id", dataPageId);
            }
        });
    }

    function checkIfChapterHasChildren (isDisplayOnlyChapters) {
        presenter.$view.find(".hier_report-chapter").each(function () {
            if($(this).next('tr[class*=treegrid-parent]').length == 0){
                if(isDisplayOnlyChapters){
                    $(this)
                        .find(`.${presenter.CSS_CLASSES.CHAPTER_EXPANDER}`)
                        .removeClass(`.${presenter.CSS_CLASSES.CHAPTER_EXPANDER_COLLAPSED}`)
                        .removeClass(`.${presenter.CSS_CLASSES.CHAPTER_EXPANDER_EXPANDED}`);
                }else{
                    $(this).remove();
                }
            }
        });
    }

    function getJqueryTable() {
        return presenter.$view.find("#" + presenter.treeID).find('table');
    }

    presenter.keyboardController = function (keycode, isShiftKeyDown, event) {
        presenter.keyboardControllerObject.handle(keycode, isShiftKeyDown, event);
    };

    function HTocKeyboardController (elements, columnsCount) {
        KeyboardController.call(this, elements, columnsCount);
    }

    HTocKeyboardController.prototype = Object.create(window.KeyboardController.prototype);
    HTocKeyboardController.prototype.constructor = HTocKeyboardController;

    presenter.buildKeyboardController = function () {
        const keyNavElements = presenter.getElementsForKeyboardNavigation();

        presenter.keyboardControllerObject = new HTocKeyboardController(keyNavElements, 1);
        presenter.keyboardControllerObject.selectEnabled(true);
    };

    presenter.getElementsForKeyboardNavigation = function () {
        const tableRows = presenter.$view.find("tbody")
            .find("tr")
            .filter((i, element) =&gt; element.className.includes("treegrid"))
            .map((i, element) =&gt; $(element));

        return tableRows.toArray();
    };

    presenter.getElementsForTTS = function() {
        const elements = presenter.getElementsForKeyboardNavigation();
        elements.unshift(presenter.getTitleElementForKeyboardNavigation());

        return elements;
    };

    presenter.getTitleElementForKeyboardNavigation = function() {
        return $(presenter.$view.find(`.${presenter.CSS_CLASSES.TITLE}`)[0]);
    };

    // Right Arrow or TAB
    HTocKeyboardController.prototype.nextElement = function (event) {
        if (event) event.preventDefault();
        this.moveToNextKeyNavElement();
    };

    // Left Arrow or SHIFT+TAB
    HTocKeyboardController.prototype.previousElement = function (event) {
        if (event) event.preventDefault();
        this.moveToPreviousKeyNavElement();
    };

    // Down Arrow
    HTocKeyboardController.prototype.nextRow = function (event) {
        if (event) event.preventDefault();
        this.moveToNextKeyNavElement();
    };

    // Up Arrow
    HTocKeyboardController.prototype.previousRow = function (event) {
        if (event) event.preventDefault();
        this.moveToPreviousKeyNavElement();
    };

    HTocKeyboardController.prototype.moveToNextKeyNavElement = function () {
        const nextIndex = this.getNextSelectableElementIndexOrNull();
        if (nextIndex === null) return;

        this.markCurrentElement(nextIndex);

        centerElement(this.keyboardNavigationCurrentElement);
    };

    HTocKeyboardController.prototype.moveToPreviousKeyNavElement = function () {
        const previousIndex = this.getPreviousSelectableElementIndexOrNull()
        if (previousIndex === null) return;

        this.markCurrentElement(previousIndex);

        centerElement(this.keyboardNavigationCurrentElement);
    };

    HTocKeyboardController.prototype.getNextSelectableElementIndexOrNull = function () {
        const elements = this.keyboardNavigationElements;
        const nextElementIndex = this.keyboardNavigationCurrentElementIndex + 1;

        for (let i = nextElementIndex; i &lt; elements.length; i++) {
            if (presenter.isParentTableRowVisible(elements[i])) {
                return i;
            }
        }
        return null;
    };

    HTocKeyboardController.prototype.getPreviousSelectableElementIndexOrNull = function () {
        const elements = this.keyboardNavigationElements;
        const nextElementIndex = this.keyboardNavigationCurrentElementIndex - 1;

        for (let i = nextElementIndex; i &gt;= 0; i--) {
            if (presenter.isParentTableRowVisible(elements[i])) {
                return i;
            }
        }
        return null;
    };

    presenter.isParentTableRowVisible = function (element) {
        return $(element).closest("tr").style('display') !== "none";
    };

    HTocKeyboardController.prototype.enter = function (event) {
        if (presenter.isFirstEnter) {
            if (presenter.isTTS()) {
                this.setElements.call(this, presenter.getElementsForTTS());
            }
            presenter.isFirstEnter = false;
        }
        KeyboardController.prototype.enter.call(this, event);
        this.readCurrentElement();
    };

    HTocKeyboardController.prototype.select = function (event) {
        if (event) event.preventDefault();
        if (!this.isSelectEnabled) {
            return;
        }

        this.selectAction();
        if (this.isCurrentElementSelectable()) {
            const $element = $(this.getCurrentElement());
            const expanderTTSPostFix = isChapterExpanderExpanded($element)
                ? presenter.speechTexts.Expanded
                : presenter.speechTexts.Collapsed;

            presenter.speak(expanderTTSPostFix);
        }
    };

    HTocKeyboardController.prototype.selectAction = function () {
        const $currentElement = $(this.getCurrentElement());

        const clickableElement = $currentElement.hasClass(presenter.CSS_CLASSES.CHAPTER)
            ? $currentElement.find(`.${presenter.CSS_CLASSES.CHAPTER_EXPANDER}`)
            : $currentElement.find("a");

        this.getTarget(clickableElement, true).click();
    };


    HTocKeyboardController.prototype.markCurrentElement = function (nextIndex) {
        KeyboardController.prototype.markCurrentElement.call(this, nextIndex);
        if(this.isCurrentElementDisplayed()) {
            this.readCurrentElement();
        }
    };

    HTocKeyboardController.prototype.readCurrentElement = function () {
        const $element = this.getTarget(this.keyboardNavigationCurrentElement, false);

        if ($element.hasClass(presenter.CSS_CLASSES.TITLE)) {
            presenter.speak(getTitleTTS($element));
        } else if ($element.hasClass(presenter.CSS_CLASSES.CHAPTER)) {
            presenter.speak(getChapterTTS($element));
        } else {
            presenter.speak(getHyperLinkTTS($element));
        }
    };

    HTocKeyboardController.prototype.isCurrentElementDisplayed = function () {
        const currentElement = this.getCurrentElement();
        return presenter.isParentTableRowVisible(currentElement);
    };

    HTocKeyboardController.prototype.isCurrentElementSelectable = function () {
        const currentElement = this.getCurrentElement();
        return !($(currentElement).hasClass("hier_report-header"));
    };

    HTocKeyboardController.prototype.getCurrentElement = function () {
        return this.getTarget(this.keyboardNavigationCurrentElement, false);
    };

    HTocKeyboardController.prototype.exitWCAGMode = function () {
        presenter.isFirstEnter = true;
        this.setElements.call(this, presenter.getElementsForKeyboardNavigation());
        KeyboardController.prototype.exitWCAGMode.call(this);
        presenter.setWCAGStatus(false);
    };

    function getTitleTTS($element) {
        const textVoiceObject = [];

        const titlePrefix = presenter.speechTexts.Title;
        pushMessageToTextVoiceObjectWithLanguageFromLesson(textVoiceObject, titlePrefix);

        const titleText = $element[0].innerText;
        pushMessageToTextVoiceObjectWithLanguageFromPresenter(textVoiceObject, titleText);

        return textVoiceObject;
    }

    function getChapterTTS ($element) {
        const textVoiceObject = [];

        const chapterPrefix = presenter.speechTexts.Chapter;
        pushMessageToTextVoiceObjectWithLanguageFromLesson(textVoiceObject, chapterPrefix);

        const chapterName = $element.find(".text-wrapper").text();
        pushMessageToTextVoiceObjectWithLanguageFromPresenter(textVoiceObject, chapterName);

        const expanderStatus = isChapterExpanderExpanded($element)
            ? presenter.speechTexts.Expanded
            : presenter.speechTexts.Collapsed;

        pushMessageToTextVoiceObjectWithLanguageFromLesson(textVoiceObject, expanderStatus);

        return textVoiceObject;
    }

    function getHyperLinkTTS($element) {
        const textVoiceObject = [];

        const goToPagePrefix = presenter.speechTexts.GoToPage;
        pushMessageToTextVoiceObjectWithLanguageFromLesson(textVoiceObject, goToPagePrefix);

        const pageName = $element[0].innerText;
        pushMessageToTextVoiceObjectWithLanguageFromPresenter(textVoiceObject, pageName);

        return textVoiceObject;
    }

    function pushMessageToTextVoiceObjectWithLanguageFromLesson(textVoiceObject, message) {
        textVoiceObject.push(window.TTSUtils.getTextVoiceObject(message));
    }

    function pushMessageToTextVoiceObjectWithLanguageFromPresenter(textVoiceObject, message) {
        textVoiceObject.push(window.TTSUtils.getTextVoiceObject(message, presenter.configuration.langTag));
    }

    function centerElement(element){
        scrollVertically(element);
    }

    function scrollVertically(element) {
        let pos = $(element).position().top;
        let currentScroll = presenter.$view.find(`.${presenter.CSS_CLASSES.TABLE_CONTAINER}`).scrollTop();
        let divHeight =  presenter.$view.find(`.${presenter.CSS_CLASSES.TABLE_CONTAINER}`).height();

        pos=(pos+currentScroll)-(divHeight/2);

        presenter.$view.find(`.${presenter.CSS_CLASSES.TABLE_CONTAINER}`).scrollTop(pos);
    }

    function isChapterExpanderExpanded ($element) {
        return $element
            .find(`.${presenter.CSS_CLASSES.CHAPTER_EXPANDER}`)
            .hasClass(presenter.CSS_CLASSES.CHAPTER_EXPANDER_EXPANDED);
    }

    presenter.setWCAGStatus = function(isWCAGOn) {
        presenter.isWCAGOn = isWCAGOn;
    };

    presenter.speak = function(data) {
        const tts = presenter.getTextToSpeechOrNull(presentationController);
        if (tts &amp;&amp; presenter.isWCAGOn) {
            tts.speak(data);
        }
    };

    presenter.isTTS = function () {
        return presenter.getTextToSpeechOrNull(presentationController) &amp;&amp; presenter.isWCAGOn;
    };

    presenter.getTextToSpeechOrNull = function HToc_getTextToSpeechOrNull(playerController) {
        if (playerController) {
            return playerController.getModule('Text_To_Speech1');
        }

        return null;
    };

    return presenter;
}
</presenter></addon>