src/modules/quran/quran.module.ts

Summary

Maintainability
A
2 hrs
Test Coverage
import { QuranService } from './quran.service';
import { DefaultResponse } from '../../_models';
import { Surah, SurahList } from './quran.model';
import { Module } from '../../libs';
import quranTemplate from './quran.template.html';
import surahTemplate from './surah.template.html';

export default class QuranModule extends Module {

    private data: SurahList;
    private currentSurah: Surah;

    protected events = {
        'quran.top': { control: 'up', title: 'بالا', icon: 'up', button: false },
        'quran.bottom': { control: 'down', title: 'پایین', icon: 'bottom', button: false },
        'quran.left': { control: 'left', title: 'چپ', icon: 'left', button: false },
        'quran.right': { control: 'right', title: 'راست', icon: 'right', button: false },
        'quran.enter': { control: 'enter', title: 'نمایش متن', icon: 'enter' },
        'quran.toggle': { control: 'blue,b', title: 'نمایش ترجمه' },
        'quran.up': { control: 'up', title: 'اسکرول بالا', icon: 'up', button: false },
        'quran.down': { control: 'down', title: 'اسکرول پایین', icon: 'bottom', button: false },
        'quran.back': { control: 'back,backspace', title: 'بازگشت به سوره‌ها', icon: 'refresh' },
    };

    constructor(config?, layoutInstance?, moduleType?: string) {
        super(config, layoutInstance, moduleType);
        this.service = QuranService.instance;
        this.events = this.prepareControls();
        this.load();
        return this;
    }

    public load(): void {
        const self = this;
        this.templateHelper.loading();
        this.service.getSurahList().done((data: DefaultResponse) => {
            // End loading
            self.data = data.data;
            self.render(self.data, () => {
                self.templateHelper.loading(false);
                self.initializeSurahListSlider();
            });
        });
    }

    public render(data: SurahList, callback): void {
        this.templateHelper.render(quranTemplate, data, this.$el, 'html', function () {
            if (typeof callback === 'function')
                callback();
        });
    }

    private initializeSurahListSlider(): void {
        const $el = $("#surah-list");
        $el.find('li:first').addClass('active');
        this.registerKeyboardInputs($el);
    }

    private navigateSurahList(index: number, $el = $("#surah-list")): void {
        const $current = $el.find('li.active:first');
        const $next = $el.find('li').eq($current.index() + index);
        $current.removeClass('active');
        if ($next.length) {
            $next.addClass('active');
            const distance = $next.offset().top - $el.offset().top + $el.scrollTop();
            if ($el.scrollTop() !== distance) {
                $el.animate({ 'scrollTop': distance }, 150);
            }
        } else {
            const $first = $el.find('li').eq(0);
            $first.addClass('active');
            $el.animate({ 'scrollTop': 0 }, 150);
        }
    }

    private registerKeyboardInputs($el = $("#surah-list")): void {
        const self = this;
        this.input.addEvent('up', false, this.events['quran.top'], () => {
            self.navigateSurahList(-4);
        });
        this.input.addEvent('down', false, this.events['quran.bottom'], () => {
            self.navigateSurahList(4);
        });
        this.input.addEvent('left', false, this.events['quran.left'], () => {
            self.navigateSurahList(1);
        });
        this.input.addEvent('right', false, this.events['quran.right'], () => {
            self.navigateSurahList(-1);
        });
        self.input.addEvent('enter', false, this.events['quran.enter'], () => {
            self.loadSurah(~~$el.find('li.active').data('id'));
        });
    }

    private loadSurah(surahId: number): void {
        const self = this;
        this.templateHelper.loading();
        this.service.getSurah(surahId).done((data: DefaultResponse) => {
            self.currentSurah = data.data;
            self.renderSurah(self.currentSurah, (data: any) => {
                self.templateHelper.loading(false);
                self.registerSurahKeyboardInputs();
                self.initLineHighlighter();
            });
        });
    }

    private renderSurah(data: Surah, callback?): void {
        this.templateHelper.render(surahTemplate, data, $('#surah'), 'html', function () {
            if (typeof callback === 'function')
                callback(data);
        });
    }

    private registerSurahKeyboardInputs(): void {
        const self = this;

        if (this.destroyEvents(this)) {
            this.input.removeEvent('back,backspace', { key: 'module.exit' });
            this.input.addEvent('back,backspace', false, this.events['quran.back'], () => {
                self.unloadSurah();
            });
            this.input.addEvent('blue,b', false, this.events['quran.toggle'], () => {
                $('.edition').toggleClass('active');
            });
            this.input.addEvent('up', false, this.events['quran.up'], () => {
                const $edition = $('.edition.active');
                const position = $edition.scrollTop() - self.getAyahLineHeight();
                $edition.animate({
                    scrollTop: position <= 0 ? 0 : position
                }, 300);
            });
            this.input.addEvent('down', false, this.events['quran.down'], () => {
                const $edition = $('.edition.active');
                const position = $edition.scrollTop() + self.getAyahLineHeight();
                $edition.animate({ scrollTop: position }, 300);
            });
        }
    }

    private initLineHighlighter(): void {
        const $highlight = $('.active-line:first');
        const $surahBody = $('.surah-body');
        if ($('.surah-header').offset().top > 30)
            $highlight.css({ 'top': $surahBody.offset().top });
    }

    private getAyahLineHeight(): number {
        return parseInt($('.edition.active').find('.surah-body').css('line-height'));
    }

    private unloadSurah(): void {
        const self = this;
        $('#surah').empty();
        this.input.removeEvent('back,backspace', { key: 'quran.back' });
        this.input.removeEvent('up', { key: 'quran.up' });
        this.input.removeEvent('down', { key: 'quran.down' });
        this.input.removeEvent('blue,b', { key: 'quran.toggle' });
        this.registerKeyboardInputs();
        setTimeout(() => {
            self.layoutInstance.prepareUnloadModule();
        }, 500);
    }

}