├── docs ├── admin.py ├── models.py ├── tests │ ├── __init__.py │ └── test_apps.py ├── migrations │ └── __init__.py ├── __init__.py ├── locale │ ├── ar │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── en │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── apps.py ├── urls.py ├── views.py └── templates │ ├── _base.html │ ├── menu.html │ └── docs │ └── index.html ├── .env ├── data_text ├── __init__.py ├── README.md ├── parse_quran_text.py └── parse_tafseer_text.py ├── tafseer_api ├── __init__.py ├── wsgi.py ├── urls.py └── settings.py ├── quran_text ├── tests │ ├── __init__.py │ ├── test_apps.py │ ├── test_serializers.py │ ├── test_urls.py │ ├── test_views.py │ └── test_models.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── __init__.py ├── locale │ ├── ar │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── en │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── apps.py ├── urls.py ├── admin.py ├── serializers.py ├── views.py └── models.py ├── quran_tafseer ├── tests │ ├── __init__.py │ ├── test_apps.py │ ├── test_serializers.py │ ├── test_urls.py │ ├── test_models.py │ └── test_views.py ├── migrations │ ├── __init__.py │ ├── 0002_auto_20180203_1313.py │ └── 0001_initial.py ├── __init__.py ├── locale │ ├── ar │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── en │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── apps.py ├── admin.py ├── urls.py ├── serializers.py ├── models.py └── views.py ├── static ├── img │ └── favicon.ico ├── fonts │ ├── lato │ │ ├── lato-bold.eot │ │ ├── lato-bold.ttf │ │ ├── lato-black.eot │ │ ├── lato-black.ttf │ │ ├── lato-black.woff │ │ ├── lato-bold.woff │ │ ├── lato-italic.eot │ │ ├── lato-italic.ttf │ │ ├── lato-light.eot │ │ ├── lato-light.ttf │ │ ├── lato-light.woff │ │ ├── lato-italic.woff │ │ ├── lato-regular.eot │ │ ├── lato-regular.ttf │ │ ├── lato-regular.woff │ │ ├── lato-bolditalic.eot │ │ ├── lato-bolditalic.ttf │ │ └── lato-bolditalic.woff │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ ├── glyphicons-halflings-regular.woff2 │ └── glyphicons │ │ ├── flat-ui-icons-regular.eot │ │ ├── flat-ui-icons-regular.ttf │ │ └── flat-ui-icons-regular.woff ├── js │ ├── prism.js │ └── bootstrap.min.js └── css │ ├── prism.css │ └── bootstrap-rtl.css ├── locale ├── ar │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po └── en │ └── LC_MESSAGES │ ├── django.mo │ └── django.po ├── requirements.txt ├── setup.cfg ├── .travis.yml ├── .coveragerc ├── Dockerfile ├── manage.py ├── requirements └── requirements_dev.txt ├── changelog.md ├── LICENSE ├── .gitignore ├── README.md └── dump_data └── sura.json /docs/admin.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | DEBUG=False -------------------------------------------------------------------------------- /docs/models.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data_text/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tafseer_api/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quran_text/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quran_tafseer/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quran_text/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quran_tafseer/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'docs.apps.DocsConfig' 2 | -------------------------------------------------------------------------------- /quran_text/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'quran_text.apps.QuranTextConfig' 2 | -------------------------------------------------------------------------------- /quran_tafseer/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'quran_tafseer.apps.QuranTafseerConfig' 2 | -------------------------------------------------------------------------------- /static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/img/favicon.ico -------------------------------------------------------------------------------- /locale/ar/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/locale/ar/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /static/fonts/lato/lato-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-bold.eot -------------------------------------------------------------------------------- /static/fonts/lato/lato-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-bold.ttf -------------------------------------------------------------------------------- /static/fonts/lato/lato-black.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-black.eot -------------------------------------------------------------------------------- /static/fonts/lato/lato-black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-black.ttf -------------------------------------------------------------------------------- /static/fonts/lato/lato-black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-black.woff -------------------------------------------------------------------------------- /static/fonts/lato/lato-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-bold.woff -------------------------------------------------------------------------------- /static/fonts/lato/lato-italic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-italic.eot -------------------------------------------------------------------------------- /static/fonts/lato/lato-italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-italic.ttf -------------------------------------------------------------------------------- /static/fonts/lato/lato-light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-light.eot -------------------------------------------------------------------------------- /static/fonts/lato/lato-light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-light.ttf -------------------------------------------------------------------------------- /static/fonts/lato/lato-light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-light.woff -------------------------------------------------------------------------------- /docs/locale/ar/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/docs/locale/ar/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /docs/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/docs/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /static/fonts/lato/lato-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-italic.woff -------------------------------------------------------------------------------- /static/fonts/lato/lato-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-regular.eot -------------------------------------------------------------------------------- /static/fonts/lato/lato-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-regular.ttf -------------------------------------------------------------------------------- /static/fonts/lato/lato-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-regular.woff -------------------------------------------------------------------------------- /static/fonts/lato/lato-bolditalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-bolditalic.eot -------------------------------------------------------------------------------- /static/fonts/lato/lato-bolditalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-bolditalic.ttf -------------------------------------------------------------------------------- /static/fonts/lato/lato-bolditalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/lato/lato-bolditalic.woff -------------------------------------------------------------------------------- /quran_text/locale/ar/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/quran_text/locale/ar/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /quran_text/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/quran_text/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /quran_tafseer/locale/ar/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/quran_tafseer/locale/ar/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /quran_tafseer/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/quran_tafseer/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /static/fonts/glyphicons/flat-ui-icons-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/glyphicons/flat-ui-icons-regular.eot -------------------------------------------------------------------------------- /static/fonts/glyphicons/flat-ui-icons-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/glyphicons/flat-ui-icons-regular.ttf -------------------------------------------------------------------------------- /static/fonts/glyphicons/flat-ui-icons-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quran-Tafseer/tafseer_api/HEAD/static/fonts/glyphicons/flat-ui-icons-regular.woff -------------------------------------------------------------------------------- /docs/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DocsConfig(AppConfig): 5 | name = 'docs' 6 | verbose_name = 'Quran Tafseer REST API Documentation' 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==2.2.28 2 | djangorestframework==3.11.2 3 | django-cors-headers==3.7.0 4 | pytz==2017.2 5 | django-environ==0.4.4 6 | django-filter==2.4.0 7 | django-prometheus==2.2.0 8 | psycopg2==2.8.5 9 | sentry-sdk==1.12.1 -------------------------------------------------------------------------------- /docs/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | url(r'^$', view=views.IndexView.as_view()), 7 | url(r'^docs/$', view=views.DocView.as_view(), name='doc-index') 8 | ] 9 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [isort] 2 | default_section = THIRDPARTY 3 | known_first_party = tafseer_api # change it for the name of your django project 4 | known_django = django 5 | sections = FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER 6 | -------------------------------------------------------------------------------- /quran_text/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class QuranTextConfig(AppConfig): 8 | name = 'quran_text' 9 | verbose_name = 'Quran Text REST API' 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: python 4 | 5 | python: 6 | - "3.5" 7 | - "3.6" 8 | install: 9 | - pip install -r requirements/requirements_dev.txt 10 | script: 11 | - coverage run manage.py test 12 | 13 | after_success: 14 | - codecov 15 | -------------------------------------------------------------------------------- /quran_tafseer/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class QuranTafseerConfig(AppConfig): 8 | name = 'quran_tafseer' 9 | verbose_name = 'Quran Tafseer REST API' 10 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | 4 | omit = *migrations* 5 | */tests/* 6 | data_text/* 7 | tafseer_api/wsgi.py 8 | manage.py 9 | 10 | source = . 11 | 12 | [html] 13 | directory = htmlcov 14 | title = Tafseer API Test Coverage Report 15 | -------------------------------------------------------------------------------- /docs/views.py: -------------------------------------------------------------------------------- 1 | from django.urls import reverse_lazy 2 | from django.views.generic import RedirectView, TemplateView 3 | 4 | 5 | class DocView(TemplateView): 6 | template_name = 'docs/index.html' 7 | 8 | 9 | class IndexView(RedirectView): 10 | url = reverse_lazy('doc-index') 11 | -------------------------------------------------------------------------------- /data_text/README.md: -------------------------------------------------------------------------------- 1 | ![Tanzil Logo](http://tanzil.net/docs/_media/wiki/logo.png) 2 | 3 | In this folder is the raw data of Quran text and tafseer text, the text source is [Tanzil Quran](http://tanzil.net). 4 | 5 | Please don't change this file, you can update it from [Tanzil website](http://tanzil.net/download) 6 | -------------------------------------------------------------------------------- /data_text/parse_quran_text.py: -------------------------------------------------------------------------------- 1 | from quran_text.models import Ayah 2 | 3 | with open('data_text/quran-simple.txt') as quran_text: 4 | for ayah in quran_text: 5 | sura_num, ayah_num, ayah_text = ayah.strip().split('|') 6 | Ayah.objects.create(number=ayah_num, sura_id=sura_num, text=ayah_text) 7 | -------------------------------------------------------------------------------- /quran_text/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | path('', 7 | view=views.SuraListView.as_view(), name='sura-list'), 8 | path('//', 9 | view=views.AyahTextView.as_view(), name='ayah-detail'), 10 | path('/', 11 | view=views.AyahTextView.as_view()), 12 | ] 13 | -------------------------------------------------------------------------------- /quran_text/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.contrib import admin 5 | 6 | from .models import Ayah, Sura 7 | 8 | 9 | class SuraAdmin(admin.ModelAdmin): 10 | list_display = ('index', 'name') 11 | 12 | 13 | class AyahAdmin(admin.ModelAdmin): 14 | list_display = ('sura', 'number', 'text') 15 | 16 | 17 | admin.site.register(Sura, SuraAdmin) 18 | admin.site.register(Ayah, AyahAdmin) 19 | -------------------------------------------------------------------------------- /quran_text/tests/test_apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import apps as django_apps 2 | from django.test import TestCase 3 | 4 | 5 | class TestAppConfig(TestCase): 6 | def setUp(self): 7 | self.app_config = django_apps.get_app_config('quran_text') 8 | 9 | def test_app_name(self): 10 | self.assertEqual('quran_text', self.app_config.name) 11 | 12 | def test_app_verbose_name(self): 13 | self.assertEqual('Quran Text REST API', self.app_config.verbose_name) 14 | -------------------------------------------------------------------------------- /tafseer_api/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for tafseer_api project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tafseer_api.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /quran_tafseer/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.contrib import admin 5 | 6 | from .models import Tafseer, TafseerText 7 | 8 | 9 | class TafseerAdmin(admin.ModelAdmin): 10 | pass 11 | 12 | 13 | class TafseerTextAdmin(admin.ModelAdmin): 14 | list_display = ('tafseer', 'ayah', 'text') 15 | ordering = ['pk'] 16 | 17 | 18 | admin.site.register(Tafseer, TafseerAdmin) 19 | admin.site.register(TafseerText, TafseerTextAdmin) 20 | -------------------------------------------------------------------------------- /docs/tests/test_apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import apps as django_apps 2 | from django.test import TestCase 3 | 4 | 5 | class TestAppConfig(TestCase): 6 | def setUp(self): 7 | self.app_config = django_apps.get_app_config('docs') 8 | 9 | def test_app_name(self): 10 | self.assertEqual('docs', self.app_config.name) 11 | 12 | def test_app_verbose_name(self): 13 | self.assertEqual('Quran Tafseer REST API Documentation', 14 | self.app_config.verbose_name) 15 | -------------------------------------------------------------------------------- /quran_tafseer/tests/test_apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import apps as django_apps 2 | from django.test import TestCase 3 | 4 | 5 | class TestAppConfig(TestCase): 6 | def setUp(self): 7 | self.app_config = django_apps.get_app_config('quran_tafseer') 8 | 9 | def test_app_name(self): 10 | self.assertEqual('quran_tafseer', self.app_config.name) 11 | 12 | def test_app_verbose_name(self): 13 | self.assertEqual('Quran Tafseer REST API', 14 | self.app_config.verbose_name) 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6 2 | MAINTAINER Emad Mokhtar emad@emadmokhtar.com 3 | ENV PYTHONUNBUFFERED 1 4 | ENV APP_PATH /app 5 | RUN mkdir $APP_PATH 6 | ADD . $APP_PATH 7 | 8 | WORKDIR $APP_PATH 9 | 10 | # Install requirements 11 | RUN pip install -r requirements/requirements.txt 12 | 13 | # Migrate data models 14 | RUN python manage.py migrate 15 | 16 | # Load data 17 | RUN python manage.py loaddata dump_data/sura.json 18 | RUN python manage.py loaddata dump_data/quran_text.json 19 | RUN python manage.py loaddata dump_data/tafseer.json 20 | 21 | 22 | CMD ["python3", "manage.py", "runserver", "0.0.0.0:8000"] 23 | -------------------------------------------------------------------------------- /quran_text/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | 3 | from .models import Ayah, Sura 4 | 5 | 6 | class SuraSerializer(serializers.ModelSerializer): 7 | 8 | class Meta: 9 | model = Sura 10 | fields = ['index', 'name'] 11 | 12 | 13 | class AyahSerializer(serializers.ModelSerializer): 14 | sura_index = serializers.IntegerField(source='sura.pk') 15 | sura_name = serializers.CharField(source='sura.name') 16 | ayah_number = serializers.IntegerField(source='number') 17 | 18 | class Meta: 19 | model = Ayah 20 | fields = ['sura_index', 'sura_name', 'ayah_number', 'text'] 21 | -------------------------------------------------------------------------------- /tafseer_api/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from django.conf.urls.i18n import i18n_patterns 3 | from django.contrib import admin 4 | 5 | def trigger_error(request): 6 | division_by_zero = 1 / 0 7 | 8 | urlpatterns = [ 9 | url(r'^quran/', include('quran_text.urls')), 10 | url(r'^tafseer/', include('quran_tafseer.urls')), 11 | url(r'^admin/', admin.site.urls), 12 | url(r'^api-auth/', include('rest_framework.urls', 13 | namespace='rest_framework')), 14 | url('sentry-debug/', trigger_error), 15 | url('', include('django_prometheus.urls')), 16 | ] 17 | 18 | urlpatterns += i18n_patterns(url(r'^', include('docs.urls'))) 19 | -------------------------------------------------------------------------------- /locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2017-12-20 20:15+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: tafseer_api/settings.py:93 21 | msgid "English" 22 | msgstr "" 23 | 24 | #: tafseer_api/settings.py:94 25 | msgid "Arabic" 26 | msgstr "" 27 | -------------------------------------------------------------------------------- /quran_text/locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2017-12-20 20:15+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: quran_text/models.py:13 21 | msgid "Sura" 22 | msgstr "" 23 | 24 | #: quran_text/models.py:42 25 | msgid "Number" 26 | msgstr "" 27 | -------------------------------------------------------------------------------- /quran_tafseer/locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2017-12-20 20:15+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: quran_tafseer/models.py:11 21 | msgid "Name" 22 | msgstr "" 23 | 24 | #: quran_tafseer/models.py:38 25 | msgid "Tafseer" 26 | msgstr "" 27 | -------------------------------------------------------------------------------- /quran_text/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from rest_framework import generics 5 | 6 | from .models import Ayah, Sura 7 | from .serializers import AyahSerializer, SuraSerializer 8 | 9 | 10 | class SuraListView(generics.ListAPIView): 11 | """ 12 | Returns a full list of quran's sura (chapters) sorted by the index 13 | """ 14 | serializer_class = SuraSerializer 15 | queryset = Sura.objects.all() 16 | 17 | 18 | class AyahTextView(generics.RetrieveAPIView): 19 | """ 20 | Returns Quran text for certain verse (Ayah) in a chapter (Sura) 21 | """ 22 | serializer_class = AyahSerializer 23 | lookup_field = 'number' 24 | lookup_url_kwargs = 'number' 25 | 26 | def get_queryset(self): 27 | sura_id = self.kwargs['sura_num'] 28 | qs = Ayah.objects.get_sura_text(sura_id) 29 | return qs 30 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tafseer_api.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /requirements/requirements_dev.txt: -------------------------------------------------------------------------------- 1 | autopep8==1.3.3 2 | certifi==2022.12.7 3 | chardet==3.0.4 4 | charset-normalizer==2.1.1 5 | codecov==2.0.16 6 | configparser==3.5.0 7 | coverage==4.4.2 8 | Django==2.2.28 9 | django-cors-headers==3.7.0 10 | django-environ==0.4.4 11 | django-filter==2.4.0 12 | django-prometheus==2.2.0 13 | django-silk==1.1.0 14 | djangorestframework==3.11.2 15 | drf-extensions==0.3.1 16 | drf-tracking==1.5.0 17 | enum34==1.1.6 18 | flake8==3.4.1 19 | flake8-isort==2.2.1 20 | flake8-polyfill==1.0.1 21 | gprof2dot==2016.10.13 22 | idna==2.6 23 | isort==4.2.15 24 | Jinja2==2.11.3 25 | MarkupSafe==1.1.1 26 | mccabe==0.6.1 27 | model-mommy==1.6.0 28 | prometheus-client==0.14.1 29 | psycopg2==2.8.5 30 | pycodestyle==2.3.1 31 | pyflakes==1.5.0 32 | Pygments==2.13.0 33 | python-dateutil==2.6.1 34 | pytz==2017.2 35 | requests==2.20.1 36 | sentry-sdk==1.12.1 37 | six==1.11.0 38 | sqlparse==0.2.4 39 | testfixtures==5.1.1 40 | urllib3==1.26.5 41 | -------------------------------------------------------------------------------- /quran_text/locale/ar/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2017-12-20 20:15+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " 20 | "&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" 21 | 22 | #: quran_text/models.py:13 23 | msgid "Sura" 24 | msgstr "سورة" 25 | 26 | #: quran_text/models.py:42 27 | msgid "Number" 28 | msgstr "رقم" 29 | -------------------------------------------------------------------------------- /locale/ar/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2017-12-20 20:15+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " 20 | "&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" 21 | 22 | #: tafseer_api/settings.py:93 23 | msgid "English" 24 | msgstr "الأنجليزية" 25 | 26 | #: tafseer_api/settings.py:94 27 | msgid "Arabic" 28 | msgstr "العربية" 29 | -------------------------------------------------------------------------------- /quran_tafseer/locale/ar/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2017-12-20 20:15+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " 20 | "&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" 21 | 22 | #: quran_tafseer/models.py:11 23 | msgid "Name" 24 | msgstr "أسم" 25 | 26 | #: quran_tafseer/models.py:38 27 | msgid "Tafseer" 28 | msgstr "تفسير" 29 | -------------------------------------------------------------------------------- /quran_tafseer/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | path('', 7 | view=views.TafseerView.as_view(), 8 | name='tafseer-list'), 9 | path('/', 10 | view=views.TafseerBooksDetailsView.as_view(), 11 | name='tafseer-book-details'), 12 | path('/', 13 | view=views.TafseerBooksDetailsView.as_view(),), 14 | path('///', 15 | view=views.AyahTafseerView.as_view(), 16 | name='ayah-tafseer'), 17 | path('//', 18 | view=views.AyahTafseerView.as_view()), 19 | path('////', 20 | view=views.AyahTafseerRangeView.as_view(), 21 | name='ayah-tafseer-range'), 22 | path('///', 23 | view=views.AyahTafseerRangeView.as_view()), 24 | ] 25 | -------------------------------------------------------------------------------- /quran_tafseer/migrations/0002_auto_20180203_1313.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2018-02-03 13:13 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('quran_tafseer', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='tafseer', 17 | name='author', 18 | field=models.CharField(blank=True, max_length=50, verbose_name='Author'), 19 | ), 20 | migrations.AddField( 21 | model_name='tafseer', 22 | name='book_name', 23 | field=models.CharField(blank=True, max_length=50, verbose_name='Book Name'), 24 | ), 25 | migrations.AddField( 26 | model_name='tafseer', 27 | name='language', 28 | field=models.CharField(blank=True, max_length=2, verbose_name='Language'), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | 6 | 7 | ## [1.2.0](https://github.com/EmadMokhtar/tafseer_api/milestone/3) - 2018-03-03 8 | 9 | ### Added 10 | - Add the next ayah in Tafseer endpoint response header `X-Next-Ayah`. 11 | - Logging. 12 | - Add more meta data (language, book name, and author) to Tafseer endpoint. 13 | - Get list of Tafseer by language. 14 | 15 | 16 | ## [1.1.0](https://github.com/EmadMokhtar/tafseer_api/milestone/2) - 2018-01-14 17 | 18 | ### Added 19 | - Ayah Tafseer by range of ayat in the chapter endpoint. 20 | 21 | ### Fixed 22 | - Performance improvement. 23 | - Return 404 status code in case of requesting tafseer not found. 24 | 25 | 26 | ## [1.0.0](https://github.com/EmadMokhtar/tafseer_api/milestone/1) - 2017-12-17 27 | 28 | ### Added 29 | - Implement the Tafseer API. 30 | - Test suite. 31 | - Deployment on Heroku. 32 | - Added a English and Arabic documentation. -------------------------------------------------------------------------------- /quran_tafseer/serializers.py: -------------------------------------------------------------------------------- 1 | from django.urls import reverse 2 | 3 | from rest_framework import serializers 4 | 5 | from .models import Tafseer, TafseerText 6 | 7 | 8 | class TafseerSerializer(serializers.ModelSerializer): 9 | 10 | class Meta: 11 | model = Tafseer 12 | fields = ['id', 'name', 'language', 'author', 'book_name'] 13 | 14 | 15 | class TafseerTextSerializer(serializers.ModelSerializer): 16 | tafseer_id = serializers.IntegerField(source='tafseer.id') 17 | tafseer_name = serializers.CharField(source='tafseer.name') 18 | ayah_url = serializers.SerializerMethodField() 19 | ayah_number = serializers.IntegerField(source='ayah.number') 20 | 21 | def get_ayah_url(self, obj): 22 | return reverse('ayah-detail', kwargs={'number': obj.ayah.number, 23 | 'sura_num': obj.ayah.sura.pk}) 24 | 25 | class Meta: 26 | model = TafseerText 27 | fields = ['tafseer_id', 'tafseer_name', 'ayah_url', 28 | 'ayah_number', 'text'] 29 | -------------------------------------------------------------------------------- /data_text/parse_tafseer_text.py: -------------------------------------------------------------------------------- 1 | from quran_tafseer.models import Tafseer, TafseerText 2 | from quran_text.models import Ayah 3 | 4 | 5 | def parse_tafseer_file(file_name, tafseer_name): 6 | with open(file_name, 'r') as tafseer_file: 7 | tafseer = Tafseer.objects.create(name=tafseer_name) 8 | for line in tafseer_file: 9 | sura, ayah, text = line.strip().split('|') 10 | ayah_obj = Ayah.objects.get(number=ayah, sura_id=sura) 11 | TafseerText.objects.create(ayah=ayah_obj, 12 | text=text, 13 | tafseer=tafseer) 14 | print('Done parsing file {} and create {} tafseer'.format(file_name, 15 | tafseer_name) 16 | ) 17 | 18 | 19 | def parse_tafseer_muyassar(): 20 | parse_tafseer_file('data_text/ar.muyassar.txt', 'التفسير الميسر') 21 | 22 | 23 | def parse_tafseer_jalalayn(): 24 | parse_tafseer_file('data_text/ar.jalalayn.txt', 'تفسير الجلالين') 25 | -------------------------------------------------------------------------------- /quran_text/tests/test_serializers.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.test import TestCase 4 | 5 | from model_mommy import mommy 6 | 7 | from ..serializers import AyahSerializer, SuraSerializer 8 | 9 | 10 | class QuranTextSerializer(TestCase): 11 | def setUp(self): 12 | self.sura = mommy.make('quran_text.sura', name='Al-Fateha', index=1) 13 | self.ayah = mommy.make('quran_text.ayah', number=1, sura=self.sura, 14 | text='بسم الله الرحمن الرحيم') 15 | 16 | def test_sura_serailizer(self): 17 | expected = { 18 | 'index': 1, 19 | 'name': 'Al-Fateha' 20 | } 21 | serializer = SuraSerializer(self.sura) 22 | self.assertDictEqual(expected, serializer.data) 23 | 24 | def test_ayah_serializer(self): 25 | expected = { 26 | 'sura_index': 1, 27 | 'sura_name': 'Al-Fateha', 28 | 'ayah_number': 1, 29 | 'text': 'بسم الله الرحمن الرحيم' 30 | } 31 | serializer = AyahSerializer(self.ayah) 32 | self.assertDictEqual(expected, serializer.data) 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Emad Mokhtar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /quran_text/tests/test_urls.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from model_mommy import mommy 4 | 5 | from ..models import Ayah, Sura 6 | 7 | 8 | class TestQuranTextEndpointsURI(TestCase): 9 | @classmethod 10 | def setUpTestData(cls): 11 | cls.sura = mommy.make(Sura, name='Al-Fateha', index=1) 12 | cls.ayah = mommy.make(Ayah, number=1, sura=cls.sura, 13 | text='بسم الله الرحمن الرحيم') 14 | 15 | def test_sura_list_url_with_tail_slash(self): 16 | url_with_tail_slash = '/quran/' 17 | self.assertEqual(200, self.client.get(url_with_tail_slash).status_code) 18 | 19 | def test_sura_list_url_without_tail_slash(self): 20 | url_without_tail_slash = '/quran' 21 | # Root URL can't accept url without tail 22 | self.assertEqual(301, self.client.get(url_without_tail_slash).status_code) 23 | 24 | def test_sura_details_url_with_tail_slash(self): 25 | url_with_tail_slash = '/quran/1/1/' 26 | self.assertEqual(200, self.client.get(url_with_tail_slash).status_code) 27 | 28 | def test_sura_details_url_without_tail_slash(self): 29 | url_without_tail_slash = '/quran/1/1' 30 | self.assertEqual(200, self.client.get(url_without_tail_slash).status_code) 31 | -------------------------------------------------------------------------------- /quran_tafseer/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.3 on 2017-08-06 12:40 3 | from __future__ import unicode_literals 4 | 5 | import django.db.models.deletion 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ('quran_text', '0001_initial'), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Tafseer', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('name', models.CharField(max_length=20, verbose_name='Name')), 23 | ], 24 | ), 25 | migrations.CreateModel( 26 | name='TafseerText', 27 | fields=[ 28 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 29 | ('text', models.TextField(verbose_name='Tafseer')), 30 | ('ayah', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quran_text.Ayah')), 31 | ('tafseer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quran_tafseer.Tafseer')), 32 | ], 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /quran_text/tests/test_views.py: -------------------------------------------------------------------------------- 1 | from django.urls import reverse 2 | 3 | from model_mommy import mommy 4 | from rest_framework.test import APITestCase 5 | 6 | from ..models import Ayah, Sura 7 | 8 | 9 | class TestQuranTextView(APITestCase): 10 | def setUp(self): 11 | self.al_fateha = mommy.make(Sura, name='Al-Fateha', index=1) 12 | self.al_baqrah = mommy.make(Sura, name='Al-Baqrah', index=2) 13 | self.al_fateha_ayah = mommy.make(Ayah, number=1, sura=self.al_fateha, 14 | text='بسم الله الرحمن الرحيم') 15 | self.al_baqrah_ayah = mommy.make(Ayah, number=1, sura=self.al_baqrah, 16 | text='بسم الله الرحمن الرحيم') 17 | 18 | def test_sura_list_view(self): 19 | sura_list_url = reverse('sura-list') 20 | response = self.client.get(sura_list_url) 21 | sura_list = ('[{"index":1,"name":"Al-Fateha"}' 22 | ',{"index":2,"name":"Al-Baqrah"}]') 23 | self.assertEqual(sura_list, response.content.decode()) 24 | 25 | def test_ayah_text_view(self): 26 | ayah_url = reverse('ayah-detail', kwargs={'sura_num': 1, 'number': 1}) 27 | response = self.client.get(ayah_url) 28 | ayah_text = ('{"sura_index":1,"sura_name":"Al-Fateha","ayah_number":1,' 29 | '"text":"بسم الله الرحمن الرحيم"}') 30 | self.assertEqual(ayah_text, response.content.decode()) 31 | -------------------------------------------------------------------------------- /docs/templates/_base.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | {% load i18n %} 3 | {% get_current_language_bidi as RTL %} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {% block title %} 14 | 15 | {% endblock %} 16 | 17 | 18 | 19 | 23 | {% if RTL %} 24 | 25 | {% endif %} 26 | 31 | {% block style %} 32 | {% endblock %} 33 | 34 | 35 | {% include "menu.html" %} 36 |
37 | {% block container %} 38 | {% endblock %} 39 |
40 | 41 | 42 | {% block scripts %} 43 | {% endblock %} 44 | 45 | 46 | -------------------------------------------------------------------------------- /quran_text/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.3 on 2017-08-06 12:40 3 | from __future__ import unicode_literals 4 | 5 | import django.db.models.deletion 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Ayah', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('number', models.PositiveIntegerField(verbose_name='Number')), 22 | ('text', models.TextField()), 23 | ], 24 | options={ 25 | 'ordering': ['sura', 'number'], 26 | }, 27 | ), 28 | migrations.CreateModel( 29 | name='Sura', 30 | fields=[ 31 | ('index', models.PositiveIntegerField(primary_key=True, serialize=False)), 32 | ('name', models.CharField(max_length=20, unique=True, verbose_name='Sura')), 33 | ], 34 | options={ 35 | 'ordering': ['index'], 36 | }, 37 | ), 38 | migrations.AddField( 39 | model_name='ayah', 40 | name='sura', 41 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ayat', to='quran_text.Sura'), 42 | ), 43 | migrations.AlterUniqueTogether( 44 | name='ayah', 45 | unique_together=set([('number', 'sura')]), 46 | ), 47 | ] 48 | -------------------------------------------------------------------------------- /quran_tafseer/tests/test_serializers.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from model_mommy import mommy 4 | from quran_tafseer.serializers import TafseerSerializer, TafseerTextSerializer 5 | 6 | 7 | class TestTafseerTextSeriazlier(TestCase): 8 | def setUp(self): 9 | self.sura = mommy.make('quran_text.sura', name='Al-Fateha', index=1) 10 | self.ayah = mommy.make('quran_text.ayah', number=1, sura=self.sura, 11 | text='بسم الله الرحمن الرحيم') 12 | self.tafseer = mommy.make('quran_tafseer.Tafseer', name='simple', 13 | language='ar', book_name='simple book', 14 | author='random') 15 | self.tafseer_text = mommy.make('quran_tafseer.TafseerText', 16 | ayah=self.ayah, tafseer=self.tafseer, 17 | text='بسم الله الرحمن الرحيم') 18 | 19 | def test_tafseer_serializer(self): 20 | serializer = TafseerSerializer(self.tafseer) 21 | self.assertEqual(serializer.data, {'id': 1, 'name': 'simple', 22 | 'language': 'ar', 23 | 'author': 'random', 24 | 'book_name': 'simple book'}) 25 | 26 | def test_tafseer_text_serializer(self): 27 | serializer = TafseerTextSerializer(self.tafseer_text) 28 | self.assertEqual(serializer.data, {'tafseer_id': 1, 29 | 'tafseer_name': 'simple', 30 | 'ayah_url': '/quran/1/1/', 31 | 'ayah_number': 1, 32 | 'text': 'بسم الله الرحمن الرحيم'}) 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # Jupyter Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # SageMath parsed files 79 | *.sage.py 80 | 81 | # dotenv 82 | .env 83 | 84 | # virtualenv 85 | .venv 86 | venv/ 87 | ENV/ 88 | 89 | # Spyder project settings 90 | .spyderproject 91 | .spyproject 92 | 93 | # Rope project settings 94 | .ropeproject 95 | 96 | # mkdocs documentation 97 | /site 98 | 99 | # mypy 100 | .mypy_cache/ 101 | 102 | # virtualenvwrapper 103 | .project 104 | 105 | # db 106 | db.sqlite3 107 | 108 | # MacOS 109 | .DS_Store 110 | 111 | # Pycharm 112 | .idea 113 | -------------------------------------------------------------------------------- /quran_text/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models 5 | from django.utils.translation import ugettext_lazy as _ 6 | 7 | 8 | class Sura(models.Model): 9 | """ 10 | Model to hold the Quran Chapters "Sura" 11 | """ 12 | index = models.PositiveIntegerField(primary_key=True) 13 | name = models.CharField(max_length=20, unique=True, verbose_name=_('Sura')) 14 | 15 | def __str__(self): 16 | return self.name 17 | 18 | class Meta: 19 | ordering = ['index'] 20 | 21 | 22 | class AyahManager(models.Manager): 23 | 24 | def get_sura_text(self, sura_id): 25 | """Get all sura ayat""" 26 | return self.filter(sura_id=sura_id) 27 | 28 | def get_sura_ayah(self, sura_id, ayah_num): 29 | """Get one ayah from sura""" 30 | return self.get_sura_text(sura_id).filter(number=ayah_num) 31 | 32 | def get_sura_ayat_range(self, sura_id, from_ayah, to_ayah): 33 | """Get sura ayat from range (from ayah number to ahay number)""" 34 | return self.get_sura_text(sura_id).filter(number__lte=to_ayah, 35 | number__gte=from_ayah) 36 | 37 | 38 | class Ayah(models.Model): 39 | """ 40 | Model to hold chapters' text ot Verse "Ayat" 41 | """ 42 | number = models.PositiveIntegerField(verbose_name=_('Number')) 43 | sura = models.ForeignKey(Sura, related_name='ayat', on_delete=models.CASCADE) 44 | text = models.TextField() 45 | objects = AyahManager() 46 | 47 | def next_ayah(self): 48 | try: 49 | return Ayah.objects.get(pk=self.pk+1) 50 | except Ayah.DoesNotExist: 51 | return None 52 | 53 | def __str__(self): 54 | return '{ayah.sura.index} - {ayah.number}'.format(ayah=self) 55 | 56 | class Meta: 57 | unique_together = ['number', 'sura'] 58 | ordering = ['sura', 'number'] 59 | -------------------------------------------------------------------------------- /docs/templates/menu.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% get_current_language as LANGUAGE_CODE %} 3 | {% get_language_info for LANGUAGE_CODE as lang %} 4 | {% get_available_languages as LANGUAGES %} 5 | {% get_current_language_bidi as RTL %} 6 | 39 | -------------------------------------------------------------------------------- /quran_tafseer/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models 5 | from django.utils.translation import ugettext_lazy as _ 6 | 7 | from quran_text.models import Ayah 8 | 9 | 10 | class Tafseer(models.Model): 11 | name = models.CharField(max_length=20, verbose_name=_('Name')) 12 | author = models.CharField(max_length=50, verbose_name=_('Author'), 13 | blank=True) 14 | book_name = models.CharField(max_length=50, verbose_name=_('Book Name'), 15 | blank=True) 16 | language = models.CharField(max_length=2, verbose_name=_('Language'), 17 | blank=True) 18 | 19 | def __str__(self): 20 | return self.name 21 | 22 | 23 | class TafseerTextManager(models.Manager): 24 | 25 | def get_sura_tafseer(self, tafseer_id, sura_id): 26 | return self.filter(ayah__sura_id=sura_id, 27 | tafseer_id=tafseer_id).select_related('ayah', 28 | 'ayah__sura', 29 | 'tafseer') 30 | 31 | def get_ayah_tafseer(self, tafseer_id, sura_id, ayah_num): 32 | tafseer_text = self.get_sura_tafseer(tafseer_id, sura_id).filter( 33 | ayah__number=ayah_num 34 | ).first() 35 | if not tafseer_text: 36 | raise TafseerText.DoesNotExist 37 | return tafseer_text 38 | 39 | def get_ayah_tafseer_range(self, tafseer_id, sura_id, ayah_from, ayah_to): 40 | tafseer_text = self.get_sura_tafseer(tafseer_id, sura_id).filter( 41 | ayah__number__gte=ayah_from, 42 | ayah__number__lte=ayah_to 43 | ) 44 | if not tafseer_text: 45 | raise TafseerText.DoesNotExist 46 | return tafseer_text 47 | 48 | 49 | class TafseerText(models.Model): 50 | tafseer = models.ForeignKey(Tafseer, on_delete=models.CASCADE) 51 | ayah = models.ForeignKey(Ayah, on_delete=models.CASCADE) 52 | text = models.TextField(verbose_name=_('Tafseer')) 53 | objects = TafseerTextManager() 54 | 55 | def __str__(self): 56 | return self.text 57 | -------------------------------------------------------------------------------- /quran_text/tests/test_models.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from model_mommy import mommy 4 | 5 | from ..models import Ayah, Sura 6 | 7 | 8 | class TestSuraModel(TestCase): 9 | def setUp(self): 10 | self.sura = mommy.make(Sura, name='Al-Fateha', index=1) 11 | self.ayah = mommy.make(Ayah, number=1, sura=self.sura, 12 | text='بسم الله الرحمن الرحيم') 13 | 14 | def test_str(self): 15 | self.assertEqual('Al-Fateha', str(self.sura)) 16 | 17 | 18 | class TestAyahModel(TestCase): 19 | def setUp(self): 20 | self.sura = mommy.make('quran_text.sura', name='Al-Fateha', index=1) 21 | self.ayah = mommy.make('quran_text.ayah', number=1, sura=self.sura, 22 | text='بسم الله الرحمن الرحيم') 23 | self.ayah_2 = mommy.make('quran_text.ayah', number=2, sura=self.sura, 24 | text='الحمدلله رب العالمين') 25 | 26 | def test_str(self): 27 | self.assertEqual('1 - 1', str(self.ayah)) 28 | 29 | def test_get_next_ayah(self): 30 | next_ayah = self.ayah.next_ayah() 31 | self.assertIsNotNone(next_ayah) 32 | self.assertEqual(next_ayah, self.ayah_2) 33 | 34 | def test_get_next_ayah_last_ayah(self): 35 | next_ayah = self.ayah_2.next_ayah() 36 | self.assertIsNone(next_ayah) 37 | 38 | 39 | class TestAyahModelManager(TestCase): 40 | def setUp(self): 41 | self.sura = mommy.make('quran_text.sura', name='Al-Fateha', index=1) 42 | self.ayah = mommy.make('quran_text.ayah', number=1, sura=self.sura, 43 | text='بسم الله الرحمن الرحيم') 44 | mommy.make('quran_text.ayah', number=2, sura=self.sura, 45 | text='الحمدلله رب العالمين') 46 | 47 | def test_get_sura_text(self): 48 | ayaht = Ayah.objects.get_sura_text(1) 49 | self.assertIn(self.ayah, ayaht) 50 | self.assertEqual(2, ayaht.count()) 51 | 52 | def test_get_sura_ayah(self): 53 | ayah = Ayah.objects.get_sura_ayah(1, 1) 54 | self.assertIn(self.ayah, ayah) 55 | 56 | def test_get_sura_ayat_range(self): 57 | ayaht = Ayah.objects.get_sura_ayat_range(1, 1, 2) 58 | self.assertIn(self.ayah, ayaht) 59 | self.assertEqual(2, ayaht.count()) 60 | -------------------------------------------------------------------------------- /quran_tafseer/tests/test_urls.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from model_mommy import mommy 4 | 5 | from quran_tafseer.models import Tafseer, TafseerText 6 | 7 | 8 | class TestQuranTafseerEndpointsURI(TestCase): 9 | @classmethod 10 | def setUpTestData(cls): 11 | cls.sura = mommy.make('quran_text.sura', name='Al-Fateha', index=1) 12 | cls.ayah_1 = mommy.make('quran_text.ayah', number=1, sura=cls.sura, 13 | text='بسم الله الرحمن الرحيم') 14 | cls.ayah_2 = mommy.make('quran_text.ayah', number=2, sura=cls.sura, 15 | text='الحمدلله رب العالمين') 16 | cls.tafseer = mommy.make(Tafseer, name='simple') 17 | cls.tafseer_text_1 = mommy.make(TafseerText, ayah=cls.ayah_1, 18 | tafseer=cls.tafseer, 19 | text='بسم الله الرحمن الرحيم') 20 | cls.tafseer_text_2 = mommy.make(TafseerText, ayah=cls.ayah_1, 21 | tafseer=cls.tafseer, 22 | text='الحمدلله رب العالمين') 23 | 24 | def test_tafseer_list_with_tail_slash(self): 25 | url_with_tail_slash = '/tafseer/' 26 | self.assertEqual(200, self.client.get(url_with_tail_slash).status_code) 27 | 28 | def test_tafseer_list_without_tail_slash(self): 29 | url_without_tail_slash = '/tafseer' 30 | # Root URL can't accept url without tail 31 | self.assertEqual(301, self.client.get( 32 | url_without_tail_slash).status_code) 33 | 34 | def test_ayah_tafseer_with_tail_slash(self): 35 | url_with_tail_slash = '/tafseer/1/1/1/' 36 | self.assertEqual(200, self.client.get(url_with_tail_slash).status_code) 37 | 38 | def test_ayah_tafseer_without_tail_slash(self): 39 | url_without_tail_slash = '/tafseer/1/1/1' 40 | self.assertEqual(200, self.client.get( 41 | url_without_tail_slash).status_code) 42 | 43 | def test_ayah_tafseer_range_with_tail_slash(self): 44 | url_with_tail_slash = '/tafseer/1/1/1/2/' 45 | self.assertEqual(200, self.client.get(url_with_tail_slash).status_code) 46 | 47 | def test_ayah_tafseer_range_without_tail_slash(self): 48 | url_without_tail_slash = '/tafseer/1/1/1/2' 49 | self.assertEqual(200, self.client.get( 50 | url_without_tail_slash).status_code) 51 | -------------------------------------------------------------------------------- /quran_tafseer/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from rest_framework import generics 5 | from rest_framework.exceptions import NotFound 6 | 7 | from .models import Tafseer, TafseerText 8 | from .serializers import TafseerSerializer, TafseerTextSerializer 9 | 10 | 11 | class TafseerView(generics.ListAPIView): 12 | serializer_class = TafseerSerializer 13 | queryset = Tafseer.objects.all().order_by('pk') 14 | 15 | def get_queryset(self): 16 | qs = super().get_queryset() 17 | lang = self.request.query_params.get('lang', None) 18 | if lang: 19 | qs = qs.filter(language=lang) 20 | return qs 21 | 22 | 23 | class AyahTafseerView(generics.RetrieveAPIView): 24 | serializer_class = TafseerTextSerializer 25 | model = TafseerText 26 | next_ayah = None 27 | 28 | def get_object(self): 29 | tafseer_id = self.kwargs['tafseer_id'] 30 | sura_index = self.kwargs['sura_index'] 31 | ayah_number = self.kwargs['ayah_number'] 32 | try: 33 | ayah_tafseer = TafseerText.objects.get_ayah_tafseer(tafseer_id, 34 | sura_index, 35 | ayah_number) 36 | next_ayah = ayah_tafseer.ayah.next_ayah() 37 | if next_ayah is not None: 38 | self.next_ayah = {'ayah_number': next_ayah.number, 39 | 'sura_number': next_ayah.sura.index} 40 | return ayah_tafseer 41 | except TafseerText.DoesNotExist: 42 | raise NotFound('Tafseer with provided id or ' 43 | 'with sura and ayah ids not found') 44 | 45 | def finalize_response(self, request, response, *args, **kwargs): 46 | response = super().finalize_response(request, response, *args, 47 | **kwargs) 48 | if self.next_ayah: 49 | response['X-Next-Ayah'] = "{}:{}".format( 50 | self.next_ayah['sura_number'], 51 | self.next_ayah['ayah_number']) 52 | return response 53 | 54 | 55 | class AyahTafseerRangeView(generics.ListAPIView): 56 | serializer_class = TafseerTextSerializer 57 | model = TafseerText 58 | 59 | def get_queryset(self): 60 | tafseer_id = self.kwargs['tafseer_id'] 61 | sura_index = self.kwargs['sura_index'] 62 | ayah_from = self.kwargs['ayah_from'] 63 | ayah_to = self.kwargs['ayah_to'] 64 | try: 65 | qs = TafseerText.objects.get_ayah_tafseer_range(tafseer_id, 66 | sura_index, 67 | ayah_from, ayah_to) 68 | return qs 69 | except TafseerText.DoesNotExist: 70 | raise NotFound('Tafseer with provided id, sura id, or range or ' 71 | 'ayah are not found') 72 | 73 | 74 | class TafseerBooksDetailsView(generics.RetrieveAPIView): 75 | serializer_class = TafseerSerializer 76 | model = TafseerText 77 | 78 | def get_object(self): 79 | tafseer_id = self.kwargs['tafseer_id'] 80 | try: 81 | return Tafseer.objects.get(id=tafseer_id) 82 | except Tafseer.DoesNotExist: 83 | raise NotFound('Tafseer with provided id not found') 84 | -------------------------------------------------------------------------------- /quran_tafseer/tests/test_models.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from model_mommy import mommy 4 | from quran_tafseer.models import Tafseer, TafseerText 5 | 6 | 7 | class TestTafseerModel(TestCase): 8 | def setUp(self): 9 | self.tafseer = mommy.make(Tafseer, name='simple') 10 | 11 | def test_str(self): 12 | self.assertEqual(str(self.tafseer), 'simple') 13 | 14 | 15 | class TestTafseerTextModel(TestCase): 16 | def setUp(self): 17 | self.sura = mommy.make('quran_text.sura', name='Al-Fateha', index=1) 18 | self.ayah = mommy.make('quran_text.ayah', number=1, sura=self.sura, 19 | text='بسم الله الرحمن الرحيم') 20 | self.tafseer = mommy.make(Tafseer, name='simple') 21 | self.tafseer_text = mommy.make(TafseerText, ayah=self.ayah, 22 | text='بسم الله الرحمن الرحيم') 23 | 24 | def test_str(self): 25 | self.assertEqual(str(self.tafseer_text), 'بسم الله الرحمن الرحيم') 26 | 27 | 28 | class TestTafseerTextManager(TestCase): 29 | def setUp(self): 30 | self.sura = mommy.make('quran_text.sura', name='Al-Fateha', index=1) 31 | self.ayah_1 = mommy.make('quran_text.ayah', number=1, sura=self.sura, 32 | text='بسم الله الرحمن الرحيم') 33 | self.ayah_2 = mommy.make('quran_text.ayah', number=2, sura=self.sura, 34 | text='الحمدلله رب العالمين') 35 | self.tafseer = mommy.make(Tafseer, name='simple') 36 | self.tafseer_text_1 = mommy.make(TafseerText, ayah=self.ayah_1, 37 | tafseer=self.tafseer, 38 | text='بسم الله الرحمن الرحيم') 39 | self.tafseer_text_2 = mommy.make(TafseerText, ayah=self.ayah_1, 40 | tafseer=self.tafseer, 41 | text='الحمدلله رب العالمين') 42 | 43 | def test_get_sura_tafseer(self): 44 | sura_tafseer = TafseerText.objects.get_sura_tafseer(self.tafseer.pk, 45 | self.sura.pk) 46 | self.assertEqual(2, sura_tafseer.count()) 47 | self.assertIn(self.tafseer_text_1, sura_tafseer) 48 | self.assertIn(self.tafseer_text_2, sura_tafseer) 49 | 50 | def test_ayah_tafseer(self): 51 | ayah_tafseer = TafseerText.objects.get_ayah_tafseer(self.tafseer.pk, 52 | self.sura.pk, 53 | self.ayah_1.pk) 54 | self.assertEqual(self.tafseer_text_1, ayah_tafseer) 55 | 56 | def test_get_ayah_tafseer_range(self): 57 | ayah_tafseer_range = TafseerText.objects. \ 58 | get_ayah_tafseer_range(self.tafseer.pk, 59 | self.sura.pk, 60 | 1, 2) 61 | self.assertEqual(2, ayah_tafseer_range.count()) 62 | self.assertIn(self.tafseer_text_1, ayah_tafseer_range) 63 | self.assertIn(self.tafseer_text_2, ayah_tafseer_range) 64 | 65 | def test_get_ayah_tafseer_range_with_wrong_range(self): 66 | with self.assertRaises(TafseerText.DoesNotExist): 67 | TafseerText.objects.get_ayah_tafseer_range(self.tafseer.pk, 68 | self.sura.pk, 69 | 2, 1) 70 | -------------------------------------------------------------------------------- /docs/locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2017-12-20 20:15+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: docs/templates/docs/index.html:9 21 | msgid "Quran Tafseer API - Documentation" 22 | msgstr "" 23 | 24 | #: docs/templates/docs/index.html:17 25 | msgid "Quran Tafseer" 26 | msgstr "" 27 | 28 | #: docs/templates/docs/index.html:19 29 | msgid "Main Description" 30 | msgstr "" 31 | "This is an REST APIs fro Quran Tafseer or Translation, it's a place you'll " 32 | "find most of Quran Tafseer, and it's free to use." 33 | 34 | #: docs/templates/docs/index.html:27 35 | msgid "Home" 36 | msgstr "" 37 | 38 | #: docs/templates/docs/index.html:28 39 | msgid "Chapter List" 40 | msgstr "" 41 | 42 | #: docs/templates/docs/index.html:29 43 | msgid "Verse Details" 44 | msgstr "" 45 | 46 | #: docs/templates/docs/index.html:30 47 | msgid "Tafseer List" 48 | msgstr "" 49 | 50 | #: docs/templates/docs/index.html:31 51 | msgid "Verse Tafseer" 52 | msgstr "" 53 | 54 | #: docs/templates/docs/index.html:39 55 | msgid "Chapter List Endpoint" 56 | msgstr "" 57 | 58 | #: docs/templates/docs/index.html:43 docs/templates/docs/index.html:127 59 | #: docs/templates/docs/index.html:208 docs/templates/docs/index.html:284 60 | msgid "Description" 61 | msgstr "" 62 | 63 | #: docs/templates/docs/index.html:44 64 | msgid "" 65 | "Simple API endpoint to get a list of Quran chapters, the index " 66 | "can be use in other endpoints." 67 | msgstr "" 68 | 69 | #: docs/templates/docs/index.html:47 docs/templates/docs/index.html:131 70 | #: docs/templates/docs/index.html:212 docs/templates/docs/index.html:288 71 | msgid "Request" 72 | msgstr "" 73 | 74 | #: docs/templates/docs/index.html:76 docs/templates/docs/index.html:163 75 | #: docs/templates/docs/index.html:241 docs/templates/docs/index.html:321 76 | msgid "Response" 77 | msgstr "" 78 | 79 | #: docs/templates/docs/index.html:80 docs/templates/docs/index.html:167 80 | #: docs/templates/docs/index.html:245 docs/templates/docs/index.html:325 81 | msgid "Status Codes" 82 | msgstr "" 83 | 84 | #: docs/templates/docs/index.html:92 docs/templates/docs/index.html:182 85 | #: docs/templates/docs/index.html:257 docs/templates/docs/index.html:339 86 | msgid "Body" 87 | msgstr "" 88 | 89 | #: docs/templates/docs/index.html:123 90 | msgid "Verse Details Endpoint" 91 | msgstr "" 92 | 93 | #: docs/templates/docs/index.html:128 94 | msgid "" 95 | "API endpoint to get a text for specific Verse in Sura, you should pass " 96 | "Sura number and Ayah number as query parameter." 97 | msgstr "" 98 | 99 | #: docs/templates/docs/index.html:204 100 | msgid "Tafseer List Endpoint" 101 | msgstr "" 102 | 103 | #: docs/templates/docs/index.html:209 104 | msgid "" 105 | "Simple API endpoint to get a list of Quran tafseer available in Tafseer " 106 | "API, the id can be use in other endpoints." 107 | msgstr "" 108 | 109 | #: docs/templates/docs/index.html:280 110 | msgid "Verse Tafseer Endpoint" 111 | msgstr "" 112 | 113 | #: docs/templates/docs/index.html:285 114 | msgid "" 115 | "API endpoint to get a specific tasfeer for verse in chapter, you should pass " 116 | "Tafseer Id which can get from Tafseer " 117 | "List Endpoint, Sura number, and Ayah number as " 118 | "query parameter." 119 | msgstr "" 120 | 121 | #: docs/templates/menu.html:15 122 | msgid "Quran Tafseer API docs" 123 | msgstr "" 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quran Tafseer API [![Codeship Status for Quran-Tafseer/tafseer_api](https://app.codeship.com/projects/8bc13660-dd1b-0136-eb69-5213487ae4ca/status?branch=master)](https://app.codeship.com/projects/317993) [![Build Status](https://travis-ci.org/Quran-Tafseer/tafseer_api.svg?branch=master)](https://travis-ci.org/Quran-Tafseer/tafseer_api) [![codecov](https://codecov.io/gh/EmadMokhtar/tafseer_api/branch/master/graph/badge.svg)](https://codecov.io/gh/EmadMokhtar/tafseer_api) 2 | 3 | Quran Tafseer REST APIs and Quran Text 4 | 5 | [Official Documentation](http://api.quran-tafseer.com/en/docs/) 6 | 7 | ## Idea 8 | 9 | The idea is to create one REST API for all Quran Tafseer/Interpretation for developers. 10 | The idea came to me when I tried to search for REST API for Quran Tafseer/Interpretation I couldn't find one, 11 | and each Quran application web/mobile has its own Quran Tafseer/Interpretation, so I thought it's a good idea 12 | to create one. 13 | 14 | 15 | ## How to contribute and help the project 16 | 17 | 1. [Report Bugs](https://github.com/EmadMokhtar/tafseer_api/issues/new) 18 | * If you found a bug please report, it'll help the project to grow and improve. 19 | 1. [Suggest Ideas](https://github.com/EmadMokhtar/tafseer_api/issues/new) 20 | * If you have an innovative idea you feel it'll be awesome to add to the API, please share. 21 | 1. Use the API 22 | * Yes using the API will help the project, this is the reason I built this API 😉. 23 | 1. Spread the word 24 | * Share the API with your friends and community. 25 | 1. Write a wrapper or client for the API. 26 | * Please find the client list below. 27 | 1. [Donate](https://www.paypal.me/emadhabib/1) 28 | * You can help me in growing the project with any amount. 29 | 1. Check [translation help](https://github.com/EmadMokhtar/tafseer_api/labels/translation%20help) label, and help in documentation translation. 30 | 1. Check [help wanted](https://github.com/EmadMokhtar/tafseer_api/labels/help%20wanted) label, and help in developing the API. 31 | 32 | ## Development Stack 33 | 34 | 1. [Python](https://www.python.org/) 35 | 1. [Django](https://www.djangoproject.com/) 36 | 1. [Django REST Framework](http://www.django-rest-framework.org/) 37 | 38 | ## How to run locally 39 | 40 | * Create a virtualenv 41 | `mkvirtualenv tafsser_api` 42 | * Install dependencies 43 | `pip install -r requirements/requirements_dev.txt` 44 | * Create .env file and add project settings 45 | 46 | | Setting | Example | 47 | | ------------- |:-------------:| 48 | | DEBUG | DEBUG=True | 49 | | SECRET_KEY | SECRET_KEY=VeryVerySecret | 50 | | DATABASE_URL | DATABASE_URL=sqlite:///db.sqlite3 | 51 | 52 | 53 | * Run model migrations 54 | `python manage.py migrate` 55 | * Run development server 56 | `python manage.py runserver` 57 | 58 | ## Clients 59 | 60 | * [CSharp client](https://github.com/xh0/QuranTafseerCSharpClient) created by [Bassam Abd Elhamid](https://github.com/xh0) 61 | * [Python client pytafseer](https://pypi.org/project/pytafseer/) created by [Emad Mokhtar Elsayed Habib](https://github.com/emadmokhtar) 62 | 63 | ## Quran Tafseer/Interpretation Sources 64 | 65 | | Tafseer | Soruce | Language | 66 | | ------------- |:-------------:|---------| 67 | |التفسير الميسر| [Tanzil.net](http://tanzil.net/trans/) | العربية | 68 | |تفسير الجلالي| [Tanzil.net](http://tanzil.net/trans/) | العربية 69 | |تفسير السعدي| [Ayat](http://quran.ksu.edu.sa)| العربية 70 | |تفسير ابن كثير| [Ayat](http://quran.ksu.edu.sa)| العربية 71 | |تفسير الوسيط لطنطاوي| [Ayat](http://quran.ksu.edu.sa)| العربية 72 | |تفسير البغوي| [Ayat](http://quran.ksu.edu.sa)| العربية 73 | |تفسير القرطبي| [Ayat](http://quran.ksu.edu.sa)| العربية 74 | |تفسير الطبري| [Ayat](http://quran.ksu.edu.sa)| العربية 75 | Arberry | [Tanzil.net](http://tanzil.net/trans/) | English | 76 | Yusuf Ali | [Tanzil.net](http://tanzil.net/trans/) |English | 77 | Keyzer | [Tanzil.net](http://tanzil.net/trans/) | Dutch | 78 | Leemhuis | [Tanzil.net](http://tanzil.net/trans/) | Dutch | 79 | Siregar | [Tanzil.net](http://tanzil.net/trans/) | Dutch | 80 | -------------------------------------------------------------------------------- /tafseer_api/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | from django.utils.translation import ugettext_lazy as _ 3 | import environ 4 | import sentry_sdk 5 | from sentry_sdk.integrations.django import DjangoIntegration 6 | 7 | # Initialize environ 8 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 9 | env = environ.Env(DEBUG=(bool, False),) 10 | env_file_path = os.path.join(BASE_DIR, '.env') 11 | environ.Env.read_env(env_file_path) # reading .env file 12 | 13 | # SECURITY WARNING: don't run with debug turned on in production! 14 | DEBUG = env.bool('DEBUG') 15 | 16 | SECRET_KEY = env('SECRET_KEY') 17 | 18 | ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[]) 19 | 20 | # Application definition 21 | 22 | INSTALLED_APPS = [ 23 | 'django.contrib.admin', 24 | 'django.contrib.auth', 25 | 'django.contrib.contenttypes', 26 | 'django.contrib.sessions', 27 | 'django.contrib.messages', 28 | 'django.contrib.staticfiles', 29 | # 3rd party Apps 30 | 'rest_framework', 31 | 'corsheaders', 32 | 'django_prometheus', 33 | # Internal Apps 34 | 'quran_text', 35 | 'quran_tafseer', 36 | 'docs', 37 | ] 38 | 39 | PRE_MIDDLEWARE = env.list('PRE_MIDDLEWARE', default=[]) 40 | 41 | POST_MIDDLEWARE = env.list('POST_MIDDLEWARE', default=[]) 42 | 43 | MIDDLEWARE = PRE_MIDDLEWARE + [ 44 | 'django_prometheus.middleware.PrometheusBeforeMiddleware', 45 | 'django.middleware.security.SecurityMiddleware', 46 | 'django.contrib.sessions.middleware.SessionMiddleware', 47 | 'django.middleware.locale.LocaleMiddleware', 48 | 'corsheaders.middleware.CorsMiddleware', 49 | 'django.middleware.common.CommonMiddleware', 50 | 'django.middleware.csrf.CsrfViewMiddleware', 51 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 52 | 'django.contrib.messages.middleware.MessageMiddleware', 53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 54 | 'django_prometheus.middleware.PrometheusAfterMiddleware', 55 | ] + POST_MIDDLEWARE 56 | 57 | ROOT_URLCONF = 'tafseer_api.urls' 58 | 59 | TEMPLATES = [ 60 | { 61 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 62 | 'DIRS': [], 63 | 'APP_DIRS': True, 64 | 'OPTIONS': { 65 | 'context_processors': [ 66 | 'django.template.context_processors.debug', 67 | 'django.template.context_processors.request', 68 | 'django.contrib.auth.context_processors.auth', 69 | 'django.contrib.messages.context_processors.messages', 70 | ], 71 | }, 72 | }, 73 | ] 74 | 75 | WSGI_APPLICATION = env('WSGI_APPLICATION', default='tafseer_api.wsgi.application') 76 | 77 | 78 | DATABASES = {'default': env.db()} 79 | 80 | AUTH_PASSWORD_VALIDATORS = [ 81 | { 82 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 83 | }, 84 | { 85 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 86 | }, 87 | { 88 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 89 | }, 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 92 | }, 93 | ] 94 | 95 | 96 | LANGUAGE_CODE = 'en' 97 | 98 | LANGUAGES = [ 99 | ('en', _('English')), 100 | ('ar', _('Arabic')) 101 | ] 102 | 103 | TIME_ZONE = 'UTC' 104 | 105 | USE_I18N = True 106 | 107 | USE_L10N = True 108 | 109 | USE_TZ = True 110 | 111 | STATIC_URL = '/static/' 112 | 113 | STATICFILES_DIRS = [ 114 | os.path.join(BASE_DIR, 'static'), 115 | ] 116 | 117 | STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 118 | 119 | # REST framework 120 | 121 | REST_FRAMEWORK_RENDERER = env.list('REST_FRAMEWORK_RENDERER', default=[]) 122 | 123 | REST_FRAMEWORK_PARSER = env.list('REST_FRAMEWORK_PARSER', default=[]) 124 | 125 | REST_FRAMEWORK = { 126 | 'DEFAULT_RENDERER_CLASSES': [ 127 | 'rest_framework.renderers.JSONRenderer', 128 | ] + REST_FRAMEWORK_RENDERER, 129 | 'DEFAULT_PARSER_CLASSES': [ 130 | 'rest_framework.parsers.JSONParser', 131 | ] + REST_FRAMEWORK_PARSER 132 | } 133 | 134 | # CORS support 135 | 136 | CORS_ALLOW_ALL_ORIGINS = True 137 | 138 | 139 | # Sentry 140 | 141 | sentry_dsn = env.str('SENTRY_DSN', None) 142 | if sentry_dsn is None: 143 | sentry_sdk.init( 144 | dsn=sentry_dsn, 145 | integrations=[ 146 | DjangoIntegration(), 147 | ], 148 | 149 | # Set traces_sample_rate to 1.0 to capture 100% 150 | # of transactions for performance monitoring. 151 | # We recommend adjusting this value in production. 152 | traces_sample_rate=1.0, 153 | 154 | # If you wish to associate users to errors (assuming you are using 155 | # django.contrib.auth) you may enable sending PII data. 156 | send_default_pii=True 157 | ) -------------------------------------------------------------------------------- /docs/locale/ar/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2017-12-20 20:15+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " 20 | "&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" 21 | 22 | #: docs/templates/docs/index.html:9 23 | msgid "Quran Tafseer API - Documentation" 24 | msgstr "" 25 | 26 | #: docs/templates/docs/index.html:17 27 | msgid "Quran Tafseer" 28 | msgstr "تفاسيير القرآن" 29 | 30 | #: docs/templates/docs/index.html:19 31 | msgid "Main Description" 32 | msgstr "" 33 | "واجهة لصناعة التطبيقات خاصة بتفسير القرآن الكريم تتيح لمطورين البرامج " 34 | "أستخدامها بدون مقابل مادي" 35 | 36 | #: docs/templates/docs/index.html:27 37 | msgid "Home" 38 | msgstr "الرئيسية" 39 | 40 | #: docs/templates/docs/index.html:28 41 | msgid "Chapter List" 42 | msgstr "أسماء السور" 43 | 44 | #: docs/templates/docs/index.html:29 45 | msgid "Verse Details" 46 | msgstr "معلومات عن الآيه" 47 | 48 | #: docs/templates/docs/index.html:30 49 | msgid "Tafseer List" 50 | msgstr "التفاسير المتاحة" 51 | 52 | #: docs/templates/docs/index.html:31 53 | msgid "Verse Tafseer" 54 | msgstr "تفسير الآيه" 55 | 56 | #: docs/templates/docs/index.html:39 57 | msgid "Chapter List Endpoint" 58 | msgstr "نقطة الإتصال بأسماء السور" 59 | 60 | #: docs/templates/docs/index.html:43 docs/templates/docs/index.html:127 61 | #: docs/templates/docs/index.html:208 docs/templates/docs/index.html:284 62 | msgid "Description" 63 | msgstr "الوصف" 64 | 65 | #: docs/templates/docs/index.html:44 66 | msgid "" 67 | "Simple API endpoint to get a list of Quran chapters, the index " 68 | "can be use in other endpoints." 69 | msgstr "" 70 | "نقطة إتصال لمعرفة كل سور القرآن مع رقمها يمكن أستخدام رقم السورة في نقاط " 71 | "الإتصال الآخرى" 72 | 73 | #: docs/templates/docs/index.html:47 docs/templates/docs/index.html:131 74 | #: docs/templates/docs/index.html:212 docs/templates/docs/index.html:288 75 | msgid "Request" 76 | msgstr "" 77 | 78 | #: docs/templates/docs/index.html:76 docs/templates/docs/index.html:163 79 | #: docs/templates/docs/index.html:241 docs/templates/docs/index.html:321 80 | #, fuzzy 81 | #| msgid "Response body" 82 | msgid "Response" 83 | msgstr "محتوى الرسالة المستقبلة" 84 | 85 | #: docs/templates/docs/index.html:80 docs/templates/docs/index.html:167 86 | #: docs/templates/docs/index.html:245 docs/templates/docs/index.html:325 87 | msgid "Status Codes" 88 | msgstr "" 89 | 90 | #: docs/templates/docs/index.html:92 docs/templates/docs/index.html:182 91 | #: docs/templates/docs/index.html:257 docs/templates/docs/index.html:339 92 | msgid "Body" 93 | msgstr "" 94 | 95 | #: docs/templates/docs/index.html:123 96 | msgid "Verse Details Endpoint" 97 | msgstr "نقطة الإتصال الخاصة بمعلومات الآيه" 98 | 99 | #: docs/templates/docs/index.html:128 100 | msgid "" 101 | "API endpoint to get a text for specific Verse in Sura, you should pass " 102 | "Sura number and Ayah number as query parameter." 103 | msgstr "نقطة إتصال تتيح لك معرفة محتوى الآيه في القرآن الكريم" 104 | 105 | #: docs/templates/docs/index.html:204 106 | msgid "Tafseer List Endpoint" 107 | msgstr "نقطة الإتصال الخاصة بالتفاسير المتاحة" 108 | 109 | #: docs/templates/docs/index.html:209 110 | #, fuzzy 111 | #| msgid "" 112 | #| "Simple API endpoint to get a list of Quran tafseer avaliable in " 113 | #| "Tafseer API, the id can be use in other endpoints." 114 | msgid "" 115 | "Simple API endpoint to get a list of Quran tafseer available in Tafseer " 116 | "API, the id can be use in other endpoints." 117 | msgstr "نقطة إتصال تتيح لك معرفة أنوع التفاسير المتاحة" 118 | 119 | #: docs/templates/docs/index.html:280 120 | msgid "Verse Tafseer Endpoint" 121 | msgstr "نقطة الإتصال الخاصة بتفسيير الآيه" 122 | 123 | #: docs/templates/docs/index.html:285 124 | msgid "" 125 | "API endpoint to get a specific tasfeer for verse in chapter, you should pass " 126 | "Tafseer Id which can get from Tafseer " 127 | "List Endpoint, Sura number, and Ayah number as " 128 | "query parameter." 129 | msgstr "نقطة إتصال تتيح لك معرفة تفسير الإيه حسب نوع التفسير" 130 | 131 | #: docs/templates/menu.html:15 132 | msgid "Quran Tafseer API docs" 133 | msgstr "شرح وسائل الإتصال الخاصة بتفاسيير القرآن " 134 | 135 | #~ msgid "" 136 | #~ "\n" 137 | #~ " Main Description\n" 138 | #~ " " 139 | #~ msgstr "واجهة برمجة التطبيقات" 140 | -------------------------------------------------------------------------------- /quran_tafseer/tests/test_views.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from django.test import TestCase 4 | from django.urls import reverse 5 | 6 | from rest_framework import status 7 | 8 | from model_mommy import mommy 9 | 10 | 11 | class TestTafseerViews(TestCase): 12 | def setUp(self): 13 | self.sura = mommy.make('quran_text.sura', name='Al-Bakarah', index=2) 14 | self.ayah = mommy.make('quran_text.ayah', number=5, sura=self.sura, 15 | text='بسم الله الرحمن الرحيم') 16 | self.ayah_2 = mommy.make('quran_text.ayah', number=6, sura=self.sura, 17 | text='الحمد لله رب العالمين') 18 | self.tafseer = mommy.make('quran_tafseer.Tafseer', name='simple', 19 | language='ar', book_name='simple book', 20 | author='random') 21 | self.tafseer_text = mommy.make('quran_tafseer.TafseerText', 22 | ayah=self.ayah, tafseer=self.tafseer, 23 | text='بسم الله الرحمن الرحيم') 24 | self.tafseer_text_2 = mommy.make('quran_tafseer.TafseerText', 25 | ayah=self.ayah_2, 26 | tafseer=self.tafseer, 27 | text='الحمد لله رب العالمين') 28 | 29 | def test_tafseer_view(self): 30 | tafseer_url = reverse('tafseer-list') 31 | response = self.client.get(tafseer_url) 32 | self.assertEqual(response.status_code, 200) 33 | self.assertEqual(response.content.decode(), 34 | '[{"id":1,"name":"simple","language":"ar",' 35 | '"author":"random","book_name":"simple book"}]') 36 | 37 | def test_tafseer_list_by_language(self): 38 | mommy.make('quran_tafseer.Tafseer', name='simple', 39 | language='en', book_name='simple book', 40 | author='random') 41 | tafseer_url = os.path.join(reverse('tafseer-list'), '?lang=ar') 42 | response = self.client.get(tafseer_url) 43 | self.assertEqual(response.status_code, 200) 44 | self.assertEqual(response.content.decode(), 45 | '[{"id":1,"name":"simple","language":"ar",' 46 | '"author":"random","book_name":"simple book"}]') 47 | 48 | def test_tafseer_text_view(self): 49 | tafseer_text_url = reverse('ayah-tafseer', kwargs={'tafseer_id': 1, 50 | 'sura_index': 2, 51 | 'ayah_number': 5}) 52 | response = self.client.get(tafseer_text_url) 53 | self.assertEqual(response.status_code, 200) 54 | self.assertEqual(response.content.decode(), 55 | '{"tafseer_id":1,"tafseer_name":"simple",' 56 | '"ayah_url":"/quran/2/5/","ayah_number":5,' 57 | '"text":"بسم الله الرحمن الرحيم"}') 58 | self.assertEqual(response['X-Next-Ayah'], "2:6") 59 | 60 | def test_tafseer_text_with_no_next_ayah_view(self): 61 | tafseer_text_url = reverse('ayah-tafseer', kwargs={'tafseer_id': 1, 62 | 'sura_index': 2, 63 | 'ayah_number': 6}) 64 | response = self.client.get(tafseer_text_url) 65 | self.assertEqual(response.status_code, 200) 66 | self.assertEqual(response.content.decode(), 67 | '{"tafseer_id":1,"tafseer_name":"simple",' 68 | '"ayah_url":"/quran/2/6/","ayah_number":6,' 69 | '"text":"الحمد لله رب العالمين"}') 70 | self.assertNotIn('x-next-ayah', response) 71 | 72 | def test_not_found_tafseer_404(self): 73 | """ 74 | Test if API gets invalid tafseer id or (Ayah & Sura ids) 75 | should return 404 NOT FOUND status 76 | """ 77 | tafseer_text_url = reverse('ayah-tafseer', kwargs={'tafseer_id': 0, 78 | 'sura_index': 0, 79 | 'ayah_number': 0}) 80 | response = self.client.get(tafseer_text_url) 81 | 82 | self.assertEqual(404, response.status_code) 83 | self.assertEqual( 84 | '{"detail":"Tafseer with provided id or with sura and ' 85 | 'ayah ids not found"}', 86 | response.content.decode()) 87 | with self.assertRaises(KeyError): 88 | self.assertIsNotNone(response['X-Next-Ayah']) 89 | 90 | def test_get_tafseer_range(self): 91 | """ 92 | Test getting the tafseer in the same sura but with a range of verses 93 | """ 94 | tafseer_text_url = reverse('ayah-tafseer-range', 95 | kwargs={'tafseer_id': 1, 96 | 'sura_index': 2, 97 | 'ayah_from': 5, 98 | 'ayah_to': 6}) 99 | response = self.client.get(tafseer_text_url) 100 | self.assertEqual(response.status_code, 200) 101 | self.assertEqual(response.content.decode(), 102 | '[{"tafseer_id":1,"tafseer_name":"simple",' 103 | '"ayah_url":"/quran/2/5/' 104 | '","ayah_number":5,' 105 | '"text":"بسم الله الرحمن ' 106 | 'الرحيم"},' 107 | '{"tafseer_id":1,"tafseer_name":"simple",' 108 | '"ayah_url":"/quran/2/6/","ayah_number":6,' 109 | '"text":"الحمد لله رب العالمين"}]') 110 | 111 | def test_get_tafseer_range_with_wrong_numbers(self): 112 | """ 113 | Test getting the tafseer in the same sura but with a range of verses 114 | """ 115 | # Add more ayah and its tafseer 116 | mommy.make('quran_tafseer.TafseerText', 117 | ayah=self.ayah_2, tafseer=self.tafseer, 118 | text='ألم') 119 | tafseer_text_url = reverse('ayah-tafseer-range', 120 | kwargs={'tafseer_id': 1, 121 | 'sura_index': 2, 122 | 'ayah_from': 2, 123 | 'ayah_to': 1}) 124 | response = self.client.get(tafseer_text_url) 125 | self.assertEqual(response.status_code, 404) 126 | 127 | def test_tafseer_book_details(self): 128 | """ 129 | Test getting the Quran Tafseer book details 130 | """ 131 | tafseer_book_url = reverse('tafseer-book-details', 132 | kwargs={'tafseer_id': 1}) 133 | response = self.client.get(tafseer_book_url) 134 | self.assertEqual(response.status_code, status.HTTP_200_OK) 135 | print(response.content.decode()) 136 | self.assertDictEqual(json.loads(response.content.decode()), 137 | {'id': 1, 138 | 'name': 'simple', 139 | 'language': 'ar', 140 | 'book_name': 'simple book', 141 | 'author': 'random'}) 142 | 143 | def test_tafseer_book_details_not_found(self): 144 | """ 145 | Test getting the Quran Tafseer book details with invalid ID. The API 146 | should return 404. 147 | """ 148 | tafseer_book_url = reverse('tafseer-book-details', 149 | kwargs={'tafseer_id': 9999}) 150 | response = self.client.get(tafseer_book_url) 151 | self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) 152 | -------------------------------------------------------------------------------- /static/js/prism.js: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.9.0 2 | http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript */ 3 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,disableWorkerMessageHandler:_self.Prism&&_self.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof r?new r(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/e.length)return;if(!(w instanceof s)){h.lastIndex=0;var _=h.exec(w),P=1;if(!_&&m&&b!=t.length-1){if(h.lastIndex=k,_=h.exec(e),!_)break;for(var A=_.index+(d?_[1].length:0),j=_.index+_[0].length,x=b,O=k,N=t.length;N>x&&(j>O||!t[x].type&&!t[x-1].greedy);++x)O+=t[x].length,A>=O&&(++b,k=O);if(t[b]instanceof s||t[x-1].greedy)continue;P=x-b,w=e.slice(k,O),_.index-=k}if(_){d&&(p=_[1].length);var A=_.index+p,_=_[0].slice(p),j=A+_.length,S=w.slice(0,A),C=w.slice(j),M=[b,P];S&&(++b,k+=S.length,M.push(S));var E=new s(g,f?n.tokenize(_,f):_,y,_,m);if(M.push(E),C&&M.push(C),Array.prototype.splice.apply(t,M),1!=P&&n.matchGrammar(e,t,r,b,k,!0,g),i)break}else if(i)break}}}}},tokenize:function(e,t){var r=[e],a=t.rest;if(a){for(var l in a)t[l]=a[l];delete t.rest}return n.matchGrammar(e,r,t,0,0,!1),r},hooks:{all:{},add:function(e,t){var r=n.hooks.all;r[e]=r[e]||[],r[e].push(t)},run:function(e,t){var r=n.hooks.all[e];if(r&&r.length)for(var a,l=0;a=r[l++];)a(t)}}},r=n.Token=function(e,t,n,r,a){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length,this.greedy=!!a};if(r.stringify=function(e,t,a){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return r.stringify(n,t,e)}).join("");var l={type:e.type,content:r.stringify(e.content,t,a),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:a};if(e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o=Object.keys(l.attributes).map(function(e){return e+'="'+(l.attributes[e]||"").replace(/"/g,""")+'"'}).join(" ");return"<"+l.tag+' class="'+l.classes.join(" ")+'"'+(o?" "+o:"")+">"+l.content+""},!_self.document)return _self.addEventListener?(n.disableWorkerMessageHandler||_self.addEventListener("message",function(e){var t=JSON.parse(e.data),r=t.language,a=t.code,l=t.immediateClose;_self.postMessage(n.highlight(a,n.languages[r],r)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return a&&(n.filename=a.src,n.manual||a.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener("DOMContentLoaded",n.highlightAll))),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); 4 | Prism.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype://i,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\])["']/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup; 5 | Prism.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(?:;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^{}\s][^{};]*?(?=\s*\{)/,string:{pattern:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/()[\s\S]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css",greedy:!0}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag)); 6 | Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(?:true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}; 7 | Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|\d*\.?\d+(?:[Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i,operator:/-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[[^\]\r\n]+]|\\.|[^\/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i,alias:"function"}}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\s\S]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript",greedy:!0}}),Prism.languages.js=Prism.languages.javascript; 8 | -------------------------------------------------------------------------------- /dump_data/sura.json: -------------------------------------------------------------------------------- 1 | [{"model": "quran_text.sura", "pk": 1, "fields": {"name": "\u0627\u0644\u0641\u0627\u062a\u062d\u0629"}}, {"model": "quran_text.sura", "pk": 2, "fields": {"name": "\u0627\u0644\u0628\u0642\u0631\u0629"}}, {"model": "quran_text.sura", "pk": 3, "fields": {"name": "\u0622\u0644 \u0639\u0645\u0631\u0627\u0646"}}, {"model": "quran_text.sura", "pk": 4, "fields": {"name": "\u0627\u0644\u0646\u0633\u0627\u0621"}}, {"model": "quran_text.sura", "pk": 5, "fields": {"name": "\u0627\u0644\u0645\u0627\u0626\u062f\u0629"}}, {"model": "quran_text.sura", "pk": 6, "fields": {"name": "\u0627\u0644\u0623\u0646\u0639\u0627\u0645"}}, {"model": "quran_text.sura", "pk": 7, "fields": {"name": "\u0627\u0644\u0623\u0639\u0631\u064e\u0627\u0641"}}, {"model": "quran_text.sura", "pk": 8, "fields": {"name": "\u0627\u0644\u0623\u0646\u0641\u064e\u0627\u0644"}}, {"model": "quran_text.sura", "pk": 9, "fields": {"name": "\u0627\u0644\u062a\u0648\u0628\u064e\u0629"}}, {"model": "quran_text.sura", "pk": 10, "fields": {"name": "\u064a\u064f\u0648\u0646\u0633"}}, {"model": "quran_text.sura", "pk": 11, "fields": {"name": "\u0647\u064f\u0648\u062f"}}, {"model": "quran_text.sura", "pk": 12, "fields": {"name": "\u064a\u064f\u0648\u0633\u064f\u0641"}}, {"model": "quran_text.sura", "pk": 13, "fields": {"name": "\u0627\u0644\u0631\u064e\u0651\u0639\u0652\u062f"}}, {"model": "quran_text.sura", "pk": 14, "fields": {"name": "\u0625\u0628\u0631\u0627\u0647\u0650\u064a\u0645"}}, {"model": "quran_text.sura", "pk": 15, "fields": {"name": "\u0627\u0644\u062d\u0650\u062c\u0652\u0631"}}, {"model": "quran_text.sura", "pk": 16, "fields": {"name": "\u0627\u0644\u0646\u064e\u0651\u062d\u0652\u0644"}}, {"model": "quran_text.sura", "pk": 17, "fields": {"name": "\u0627\u0644\u0625\u0633\u0652\u0631\u064e\u0627\u0621"}}, {"model": "quran_text.sura", "pk": 18, "fields": {"name": "\u0627\u0644\u0643\u0647\u0652\u0641"}}, {"model": "quran_text.sura", "pk": 19, "fields": {"name": "\u0645\u064e\u0631\u064a\u064e\u0645"}}, {"model": "quran_text.sura", "pk": 20, "fields": {"name": "\u0637\u0647"}}, {"model": "quran_text.sura", "pk": 21, "fields": {"name": "\u0627\u0644\u0623\u0646\u0628\u064a\u064e\u0627\u0621"}}, {"model": "quran_text.sura", "pk": 22, "fields": {"name": "\u0627\u0644\u062d\u064e\u062c"}}, {"model": "quran_text.sura", "pk": 23, "fields": {"name": "\u0627\u0644\u0645\u064f\u0624\u0645\u0646\u0648\u0646"}}, {"model": "quran_text.sura", "pk": 24, "fields": {"name": "\u0627\u0644\u0646\u064f\u0651\u0648\u0631"}}, {"model": "quran_text.sura", "pk": 25, "fields": {"name": "\u0627\u0644\u0641\u064f\u0631\u0652\u0642\u0627\u0646"}}, {"model": "quran_text.sura", "pk": 26, "fields": {"name": "\u0627\u0644\u0634\u064f\u0651\u0639\u064e\u0631\u064e\u0627\u0621"}}, {"model": "quran_text.sura", "pk": 27, "fields": {"name": "\u0627\u0644\u0646\u064e\u0651\u0645\u0652\u0644"}}, {"model": "quran_text.sura", "pk": 28, "fields": {"name": "\u0627\u0644\u0642\u064e\u0635\u064e\u0635"}}, {"model": "quran_text.sura", "pk": 29, "fields": {"name": "\u0627\u0644\u0639\u064e\u0646\u0643\u0628\u0648\u062a"}}, {"model": "quran_text.sura", "pk": 30, "fields": {"name": "\u0627\u0644\u0631\u064f\u0651\u0648\u0645"}}, {"model": "quran_text.sura", "pk": 31, "fields": {"name": "\u0644\u0642\u0645\u064e\u0627\u0646"}}, {"model": "quran_text.sura", "pk": 32, "fields": {"name": "\u0627\u0644\u0633\u064e\u0651\u062c\u062f\u064e\u0629"}}, {"model": "quran_text.sura", "pk": 33, "fields": {"name": "\u0627\u0644\u0623\u062d\u0632\u064e\u0627\u0628"}}, {"model": "quran_text.sura", "pk": 34, "fields": {"name": "\u0633\u064e\u0628\u064e\u0623"}}, {"model": "quran_text.sura", "pk": 35, "fields": {"name": "\u0641\u064e\u0627\u0637\u0650\u0631"}}, {"model": "quran_text.sura", "pk": 36, "fields": {"name": "\u064a\u0633"}}, {"model": "quran_text.sura", "pk": 37, "fields": {"name": "\u0627\u0644\u0635\u064e\u0651\u0627\u0641\u0627\u062a"}}, {"model": "quran_text.sura", "pk": 38, "fields": {"name": "\u0635"}}, {"model": "quran_text.sura", "pk": 39, "fields": {"name": "\u0627\u0644\u0632\u064f\u0651\u0645\u064e\u0631"}}, {"model": "quran_text.sura", "pk": 40, "fields": {"name": "\u063a\u064e\u0627\u0641\u0650\u0631"}}, {"model": "quran_text.sura", "pk": 41, "fields": {"name": "\u0641\u064f\u0635\u0650\u0651\u0644\u064e\u062a\u0652"}}, {"model": "quran_text.sura", "pk": 42, "fields": {"name": "\u0627\u0644\u0634\u064f\u0651\u0648\u0631\u064e\u0649"}}, {"model": "quran_text.sura", "pk": 43, "fields": {"name": "\u0627\u0644\u0632\u064f\u0651\u062e\u0652\u0631\u064f\u0641"}}, {"model": "quran_text.sura", "pk": 44, "fields": {"name": "\u0627\u0644\u062f\u062e\u064e\u0627\u0646"}}, {"model": "quran_text.sura", "pk": 45, "fields": {"name": "\u0627\u0644\u062c\u064e\u0627\u062b\u064a\u064e\u0629"}}, {"model": "quran_text.sura", "pk": 46, "fields": {"name": "\u0627\u0644\u0623\u062d\u0652\u0642\u0627\u0641"}}, {"model": "quran_text.sura", "pk": 47, "fields": {"name": "\u0645\u062d\u064e\u0645\u064e\u0651\u062f"}}, {"model": "quran_text.sura", "pk": 48, "fields": {"name": "\u0627\u0644\u0641\u064e\u062a\u0652\u062d"}}, {"model": "quran_text.sura", "pk": 49, "fields": {"name": "\u0627\u0644\u062d\u064f\u062c\u0631\u064e\u0627\u062a"}}, {"model": "quran_text.sura", "pk": 50, "fields": {"name": "\u0642"}}, {"model": "quran_text.sura", "pk": 51, "fields": {"name": "\u0627\u0644\u0630\u064e\u0651\u0627\u0631\u064a\u064e\u0627\u062a"}}, {"model": "quran_text.sura", "pk": 52, "fields": {"name": "\u0627\u0644\u0637\u064f\u0651\u0648\u0631"}}, {"model": "quran_text.sura", "pk": 53, "fields": {"name": "\u0627\u0644\u0646\u064e\u0651\u062c\u0652\u0645"}}, {"model": "quran_text.sura", "pk": 54, "fields": {"name": "\u0627\u0644\u0642\u064e\u0645\u064e\u0631"}}, {"model": "quran_text.sura", "pk": 55, "fields": {"name": "\u0627\u0644\u0631\u064e\u0651\u062d\u0645\u0646"}}, {"model": "quran_text.sura", "pk": 56, "fields": {"name": "\u0627\u0644\u0648\u064e\u0627\u0642\u0650\u0639\u064e\u0629"}}, {"model": "quran_text.sura", "pk": 57, "fields": {"name": "\u0627\u0644\u062d\u064e\u062f\u064a\u062f"}}, {"model": "quran_text.sura", "pk": 58, "fields": {"name": "\u0627\u0644\u0645\u062c\u064e\u0627\u062f\u0644\u0629"}}, {"model": "quran_text.sura", "pk": 59, "fields": {"name": "\u0627\u0644\u062d\u064e\u0634\u0631"}}, {"model": "quran_text.sura", "pk": 60, "fields": {"name": "\u0627\u0644\u0645\u0645\u062a\u062d\u0646\u0629"}}, {"model": "quran_text.sura", "pk": 61, "fields": {"name": "\u0627\u0644\u0635\u0641"}}, {"model": "quran_text.sura", "pk": 62, "fields": {"name": "\u0627\u0644\u062c\u0645\u0639\u0629"}}, {"model": "quran_text.sura", "pk": 63, "fields": {"name": "\u0627\u0644\u0645\u0646\u0627\u0641\u0642\u0648\u0646"}}, {"model": "quran_text.sura", "pk": 64, "fields": {"name": "\u0627\u0644\u062a\u063a\u0627\u0628\u0646"}}, {"model": "quran_text.sura", "pk": 65, "fields": {"name": "\u0627\u0644\u0637\u0644\u0627\u0642"}}, {"model": "quran_text.sura", "pk": 66, "fields": {"name": "\u0627\u0644\u062a\u062d\u0631\u064a\u0645"}}, {"model": "quran_text.sura", "pk": 67, "fields": {"name": "\u0627\u0644\u0645\u0644\u0643"}}, {"model": "quran_text.sura", "pk": 68, "fields": {"name": "\u0627\u0644\u0642\u0644\u0645"}}, {"model": "quran_text.sura", "pk": 69, "fields": {"name": "\u0627\u0644\u062d\u0627\u0642\u0629"}}, {"model": "quran_text.sura", "pk": 70, "fields": {"name": "\u0627\u0644\u0645\u0639\u0627\u0631\u062c"}}, {"model": "quran_text.sura", "pk": 71, "fields": {"name": "\u0646\u0648\u062d"}}, {"model": "quran_text.sura", "pk": 72, "fields": {"name": "\u0627\u0644\u062c\u0646"}}, {"model": "quran_text.sura", "pk": 73, "fields": {"name": "\u0627\u0644\u0645\u0632\u0651\u0645\u0651\u0644"}}, {"model": "quran_text.sura", "pk": 74, "fields": {"name": "\u0627\u0644\u0645\u062f\u0651\u062b\u0631"}}, {"model": "quran_text.sura", "pk": 75, "fields": {"name": "\u0627\u0644\u0642\u064a\u0627\u0645\u0629"}}, {"model": "quran_text.sura", "pk": 76, "fields": {"name": "\u0627\u0644\u0625\u0646\u0633\u0627\u0646"}}, {"model": "quran_text.sura", "pk": 77, "fields": {"name": "\u0627\u0644\u0645\u0631\u0633\u0644\u0627\u062a"}}, {"model": "quran_text.sura", "pk": 78, "fields": {"name": "\u0627\u0644\u0646\u0628\u0623"}}, {"model": "quran_text.sura", "pk": 79, "fields": {"name": "\u0627\u0644\u0646\u0627\u0632\u0639\u0627\u062a"}}, {"model": "quran_text.sura", "pk": 80, "fields": {"name": "\u0639\u0628\u0633"}}, {"model": "quran_text.sura", "pk": 81, "fields": {"name": "\u0627\u0644\u062a\u0643\u0648\u064a\u0631"}}, {"model": "quran_text.sura", "pk": 82, "fields": {"name": "\u0627\u0644\u0625\u0646\u0641\u0637\u0627\u0631"}}, {"model": "quran_text.sura", "pk": 83, "fields": {"name": "\u0627\u0644\u0645\u0637\u0641\u0651\u0641\u064a\u0646"}}, {"model": "quran_text.sura", "pk": 84, "fields": {"name": "\u0627\u0644\u0625\u0646\u0634\u0642\u0627\u0642"}}, {"model": "quran_text.sura", "pk": 85, "fields": {"name": "\u0627\u0644\u0628\u0631\u0648\u062c"}}, {"model": "quran_text.sura", "pk": 86, "fields": {"name": "\u0627\u0644\u0637\u0627\u0631\u0642"}}, {"model": "quran_text.sura", "pk": 87, "fields": {"name": "\u0627\u0644\u0623\u0639\u0644\u0649"}}, {"model": "quran_text.sura", "pk": 88, "fields": {"name": "\u0627\u0644\u063a\u0627\u0634\u064a\u0629"}}, {"model": "quran_text.sura", "pk": 89, "fields": {"name": "\u0627\u0644\u0641\u062c\u0631"}}, {"model": "quran_text.sura", "pk": 90, "fields": {"name": "\u0627\u0644\u0628\u0644\u062f"}}, {"model": "quran_text.sura", "pk": 91, "fields": {"name": "\u0627\u0644\u0634\u0645\u0633"}}, {"model": "quran_text.sura", "pk": 92, "fields": {"name": "\u0627\u0644\u0644\u064a\u0644"}}, {"model": "quran_text.sura", "pk": 93, "fields": {"name": "\u0627\u0644\u0636\u062d\u0649"}}, {"model": "quran_text.sura", "pk": 94, "fields": {"name": "\u0627\u0644\u0634\u0631\u062d"}}, {"model": "quran_text.sura", "pk": 95, "fields": {"name": "\u0627\u0644\u062a\u064a\u0646"}}, {"model": "quran_text.sura", "pk": 96, "fields": {"name": "\u0627\u0644\u0639\u0644\u0642"}}, {"model": "quran_text.sura", "pk": 97, "fields": {"name": "\u0627\u0644\u0642\u062f\u0631"}}, {"model": "quran_text.sura", "pk": 98, "fields": {"name": "\u0627\u0644\u0628\u064a\u0646\u0629"}}, {"model": "quran_text.sura", "pk": 99, "fields": {"name": "\u0627\u0644\u0632\u0644\u0632\u0644\u0629"}}, {"model": "quran_text.sura", "pk": 100, "fields": {"name": "\u0627\u0644\u0639\u0627\u062f\u064a\u0627\u062a"}}, {"model": "quran_text.sura", "pk": 101, "fields": {"name": "\u0627\u0644\u0642\u0627\u0631\u0639\u0629"}}, {"model": "quran_text.sura", "pk": 102, "fields": {"name": "\u0627\u0644\u062a\u0643\u0627\u062b\u0631"}}, {"model": "quran_text.sura", "pk": 103, "fields": {"name": "\u0627\u0644\u0639\u0635\u0631"}}, {"model": "quran_text.sura", "pk": 104, "fields": {"name": "\u0627\u0644\u0647\u0645\u0632\u0629"}}, {"model": "quran_text.sura", "pk": 105, "fields": {"name": "\u0627\u0644\u0641\u064a\u0644"}}, {"model": "quran_text.sura", "pk": 106, "fields": {"name": "\u0642\u0631\u064a\u0634"}}, {"model": "quran_text.sura", "pk": 107, "fields": {"name": "\u0627\u0644\u0645\u0627\u0639\u0648\u0646"}}, {"model": "quran_text.sura", "pk": 108, "fields": {"name": "\u0627\u0644\u0643\u0648\u062b\u0631"}}, {"model": "quran_text.sura", "pk": 109, "fields": {"name": "\u0627\u0644\u0643\u0627\u0641\u0631\u0648\u0646"}}, {"model": "quran_text.sura", "pk": 110, "fields": {"name": "\u0627\u0644\u0646\u0635\u0631"}}, {"model": "quran_text.sura", "pk": 111, "fields": {"name": "\u0627\u0644\u0645\u0633\u062f"}}, {"model": "quran_text.sura", "pk": 112, "fields": {"name": "\u0627\u0644\u0625\u062e\u0644\u0627\u0635"}}, {"model": "quran_text.sura", "pk": 113, "fields": {"name": "\u0627\u0644\u0641\u0644\u0642"}}, {"model": "quran_text.sura", "pk": 114, "fields": {"name": "\u0627\u0644\u0646\u0651\u0627\u0633"}}] -------------------------------------------------------------------------------- /static/css/prism.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.9.0 2 | http://prismjs.com/download.html?themes=prism-okaidia&languages=json&plugins=line-highlight+line-numbers+show-invisibles+autolinker+wpd+custom-class+file-highlight+toolbar+jsonp-highlight+highlight-keywords+remove-initial-line-feed+previewer-base+previewer-color+previewer-gradient+previewer-easing+previewer-time+previewer-angle+autoloader+unescaped-markup+command-line+normalize-whitespace+keep-markup+data-uri-highlight+show-language+copy-to-clipboard */ 3 | /** 4 | * okaidia theme for JavaScript, CSS and HTML 5 | * Loosely based on Monokai textmate theme by http://www.monokai.nl/ 6 | * @author ocodia 7 | */ 8 | 9 | code[class*="language-"], 10 | pre[class*="language-"] { 11 | color: #f8f8f2; 12 | background: none; 13 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 14 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 15 | text-align: left; 16 | white-space: pre; 17 | word-spacing: normal; 18 | word-break: normal; 19 | word-wrap: normal; 20 | line-height: 1.5; 21 | 22 | -moz-tab-size: 4; 23 | -o-tab-size: 4; 24 | tab-size: 4; 25 | 26 | -webkit-hyphens: none; 27 | -moz-hyphens: none; 28 | -ms-hyphens: none; 29 | hyphens: none; 30 | } 31 | 32 | /* Code blocks */ 33 | pre[class*="language-"] { 34 | padding: 1em; 35 | margin: .5em 0; 36 | overflow: auto; 37 | border-radius: 0.3em; 38 | } 39 | 40 | :not(pre) > code[class*="language-"], 41 | pre[class*="language-"] { 42 | background: #272822; 43 | } 44 | 45 | /* Inline code */ 46 | :not(pre) > code[class*="language-"] { 47 | padding: .1em; 48 | border-radius: .3em; 49 | white-space: normal; 50 | } 51 | 52 | .token.comment, 53 | .token.prolog, 54 | .token.doctype, 55 | .token.cdata { 56 | color: slategray; 57 | } 58 | 59 | .token.punctuation { 60 | color: #f8f8f2; 61 | } 62 | 63 | .namespace { 64 | opacity: .7; 65 | } 66 | 67 | .token.property, 68 | .token.tag, 69 | .token.constant, 70 | .token.symbol, 71 | .token.deleted { 72 | color: #f92672; 73 | } 74 | 75 | .token.boolean, 76 | .token.number { 77 | color: #ae81ff; 78 | } 79 | 80 | .token.selector, 81 | .token.attr-name, 82 | .token.string, 83 | .token.char, 84 | .token.builtin, 85 | .token.inserted { 86 | color: #a6e22e; 87 | } 88 | 89 | .token.operator, 90 | .token.entity, 91 | .token.url, 92 | .language-css .token.string, 93 | .style .token.string, 94 | .token.variable { 95 | color: #f8f8f2; 96 | } 97 | 98 | .token.atrule, 99 | .token.attr-value, 100 | .token.function { 101 | color: #e6db74; 102 | } 103 | 104 | .token.keyword { 105 | color: #66d9ef; 106 | } 107 | 108 | .token.regex, 109 | .token.important { 110 | color: #fd971f; 111 | } 112 | 113 | .token.important, 114 | .token.bold { 115 | font-weight: bold; 116 | } 117 | .token.italic { 118 | font-style: italic; 119 | } 120 | 121 | .token.entity { 122 | cursor: help; 123 | } 124 | 125 | pre[data-line] { 126 | position: relative; 127 | padding: 1em 0 1em 3em; 128 | } 129 | 130 | .line-highlight { 131 | position: absolute; 132 | left: 0; 133 | right: 0; 134 | padding: inherit 0; 135 | margin-top: 1em; /* Same as .prism’s padding-top */ 136 | 137 | background: hsla(24, 20%, 50%,.08); 138 | background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); 139 | 140 | pointer-events: none; 141 | 142 | line-height: inherit; 143 | white-space: pre; 144 | } 145 | 146 | .line-highlight:before, 147 | .line-highlight[data-end]:after { 148 | content: attr(data-start); 149 | position: absolute; 150 | top: .4em; 151 | left: .6em; 152 | min-width: 1em; 153 | padding: 0 .5em; 154 | background-color: hsla(24, 20%, 50%,.4); 155 | color: hsl(24, 20%, 95%); 156 | font: bold 65%/1.5 sans-serif; 157 | text-align: center; 158 | vertical-align: .3em; 159 | border-radius: 999px; 160 | text-shadow: none; 161 | box-shadow: 0 1px white; 162 | } 163 | 164 | .line-highlight[data-end]:after { 165 | content: attr(data-end); 166 | top: auto; 167 | bottom: .4em; 168 | } 169 | 170 | .line-numbers .line-highlight:before, 171 | .line-numbers .line-highlight:after { 172 | content: none; 173 | } 174 | 175 | pre.line-numbers { 176 | position: relative; 177 | padding-left: 3.8em; 178 | counter-reset: linenumber; 179 | } 180 | 181 | pre.line-numbers > code { 182 | position: relative; 183 | white-space: inherit; 184 | } 185 | 186 | .line-numbers .line-numbers-rows { 187 | position: absolute; 188 | pointer-events: none; 189 | top: 0; 190 | font-size: 100%; 191 | left: -3.8em; 192 | width: 3em; /* works for line-numbers below 1000 lines */ 193 | letter-spacing: -1px; 194 | border-right: 1px solid #999; 195 | 196 | -webkit-user-select: none; 197 | -moz-user-select: none; 198 | -ms-user-select: none; 199 | user-select: none; 200 | 201 | } 202 | 203 | .line-numbers-rows > span { 204 | pointer-events: none; 205 | display: block; 206 | counter-increment: linenumber; 207 | } 208 | 209 | .line-numbers-rows > span:before { 210 | content: counter(linenumber); 211 | color: #999; 212 | display: block; 213 | padding-right: 0.8em; 214 | text-align: right; 215 | } 216 | .token.tab:not(:empty), 217 | .token.cr, 218 | .token.lf, 219 | .token.space { 220 | position: relative; 221 | } 222 | 223 | .token.tab:not(:empty):before, 224 | .token.cr:before, 225 | .token.lf:before, 226 | .token.space:before { 227 | color: hsl(24, 20%, 85%); 228 | position: absolute; 229 | } 230 | 231 | .token.tab:not(:empty):before { 232 | content: '\21E5'; 233 | } 234 | 235 | .token.cr:before { 236 | content: '\240D'; 237 | } 238 | 239 | .token.crlf:before { 240 | content: '\240D\240A'; 241 | } 242 | .token.lf:before { 243 | content: '\240A'; 244 | } 245 | 246 | .token.space:before { 247 | content: '\00B7'; 248 | } 249 | .token a { 250 | color: inherit; 251 | } 252 | code[class*="language-"] a[href], 253 | pre[class*="language-"] a[href] { 254 | cursor: help; 255 | text-decoration: none; 256 | } 257 | 258 | code[class*="language-"] a[href]:hover, 259 | pre[class*="language-"] a[href]:hover { 260 | cursor: help; 261 | text-decoration: underline; 262 | } 263 | pre.code-toolbar { 264 | position: relative; 265 | } 266 | 267 | pre.code-toolbar > .toolbar { 268 | position: absolute; 269 | top: .3em; 270 | right: .2em; 271 | transition: opacity 0.3s ease-in-out; 272 | opacity: 0; 273 | } 274 | 275 | pre.code-toolbar:hover > .toolbar { 276 | opacity: 1; 277 | } 278 | 279 | pre.code-toolbar > .toolbar .toolbar-item { 280 | display: inline-block; 281 | } 282 | 283 | pre.code-toolbar > .toolbar a { 284 | cursor: pointer; 285 | } 286 | 287 | pre.code-toolbar > .toolbar button { 288 | background: none; 289 | border: 0; 290 | color: inherit; 291 | font: inherit; 292 | line-height: normal; 293 | overflow: visible; 294 | padding: 0; 295 | -webkit-user-select: none; /* for button */ 296 | -moz-user-select: none; 297 | -ms-user-select: none; 298 | } 299 | 300 | pre.code-toolbar > .toolbar a, 301 | pre.code-toolbar > .toolbar button, 302 | pre.code-toolbar > .toolbar span { 303 | color: #bbb; 304 | font-size: .8em; 305 | padding: 0 .5em; 306 | background: #f5f2f0; 307 | background: rgba(224, 224, 224, 0.2); 308 | box-shadow: 0 2px 0 0 rgba(0,0,0,0.2); 309 | border-radius: .5em; 310 | } 311 | 312 | pre.code-toolbar > .toolbar a:hover, 313 | pre.code-toolbar > .toolbar a:focus, 314 | pre.code-toolbar > .toolbar button:hover, 315 | pre.code-toolbar > .toolbar button:focus, 316 | pre.code-toolbar > .toolbar span:hover, 317 | pre.code-toolbar > .toolbar span:focus { 318 | color: inherit; 319 | text-decoration: none; 320 | } 321 | 322 | .prism-previewer, 323 | .prism-previewer:before, 324 | .prism-previewer:after { 325 | position: absolute; 326 | pointer-events: none; 327 | } 328 | .prism-previewer, 329 | .prism-previewer:after { 330 | left: 50%; 331 | } 332 | .prism-previewer { 333 | margin-top: -48px; 334 | width: 32px; 335 | height: 32px; 336 | margin-left: -16px; 337 | 338 | opacity: 0; 339 | -webkit-transition: opacity .25s; 340 | -o-transition: opacity .25s; 341 | transition: opacity .25s; 342 | } 343 | .prism-previewer.flipped { 344 | margin-top: 0; 345 | margin-bottom: -48px; 346 | } 347 | .prism-previewer:before, 348 | .prism-previewer:after { 349 | content: ''; 350 | position: absolute; 351 | pointer-events: none; 352 | } 353 | .prism-previewer:before { 354 | top: -5px; 355 | right: -5px; 356 | left: -5px; 357 | bottom: -5px; 358 | border-radius: 10px; 359 | border: 5px solid #fff; 360 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75); 361 | } 362 | 363 | .prism-previewer:after { 364 | top: 100%; 365 | width: 0; 366 | height: 0; 367 | margin: 5px 0 0 -7px; 368 | border: 7px solid transparent; 369 | border-color: rgba(255, 0, 0, 0); 370 | border-top-color: #fff; 371 | } 372 | .prism-previewer.flipped:after { 373 | top: auto; 374 | bottom: 100%; 375 | margin-top: 0; 376 | margin-bottom: 5px; 377 | border-top-color: rgba(255, 0, 0, 0); 378 | border-bottom-color: #fff; 379 | } 380 | .prism-previewer.active { 381 | opacity: 1; 382 | } 383 | .prism-previewer-color { 384 | background-image: linear-gradient(45deg, #bbb 25%, transparent 25%, transparent 75%, #bbb 75%, #bbb), linear-gradient(45deg, #bbb 25%, #eee 25%, #eee 75%, #bbb 75%, #bbb); 385 | background-size: 10px 10px; 386 | background-position: 0 0, 5px 5px; 387 | } 388 | .prism-previewer-color:before { 389 | background-color: inherit; 390 | background-clip: padding-box; 391 | } 392 | 393 | .prism-previewer-gradient { 394 | background-image: linear-gradient(45deg, #bbb 25%, transparent 25%, transparent 75%, #bbb 75%, #bbb), linear-gradient(45deg, #bbb 25%, #eee 25%, #eee 75%, #bbb 75%, #bbb); 395 | background-size: 10px 10px; 396 | background-position: 0 0, 5px 5px; 397 | 398 | width: 64px; 399 | margin-left: -32px; 400 | } 401 | .prism-previewer-gradient:before { 402 | content: none; 403 | } 404 | .prism-previewer-gradient div { 405 | position: absolute; 406 | top: -5px; 407 | left: -5px; 408 | right: -5px; 409 | bottom: -5px; 410 | border-radius: 10px; 411 | border: 5px solid #fff; 412 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75); 413 | } 414 | .prism-previewer-easing { 415 | margin-top: -76px; 416 | margin-left: -30px; 417 | width: 60px; 418 | height: 60px; 419 | background: #333; 420 | } 421 | .prism-previewer-easing.flipped { 422 | margin-bottom: -116px; 423 | } 424 | .prism-previewer-easing svg { 425 | width: 60px; 426 | height: 60px; 427 | } 428 | .prism-previewer-easing circle { 429 | fill: hsl(200, 10%, 20%); 430 | stroke: white; 431 | } 432 | .prism-previewer-easing path { 433 | fill: none; 434 | stroke: white; 435 | stroke-linecap: round; 436 | stroke-width: 4; 437 | } 438 | .prism-previewer-easing line { 439 | stroke: white; 440 | stroke-opacity: 0.5; 441 | stroke-width: 2; 442 | } 443 | @-webkit-keyframes prism-previewer-time { 444 | 0% { 445 | stroke-dasharray: 0, 500; 446 | stroke-dashoffset: 0; 447 | } 448 | 50% { 449 | stroke-dasharray: 100, 500; 450 | stroke-dashoffset: 0; 451 | } 452 | 100% { 453 | stroke-dasharray: 0, 500; 454 | stroke-dashoffset: -100; 455 | } 456 | } 457 | 458 | @-o-keyframes prism-previewer-time { 459 | 0% { 460 | stroke-dasharray: 0, 500; 461 | stroke-dashoffset: 0; 462 | } 463 | 50% { 464 | stroke-dasharray: 100, 500; 465 | stroke-dashoffset: 0; 466 | } 467 | 100% { 468 | stroke-dasharray: 0, 500; 469 | stroke-dashoffset: -100; 470 | } 471 | } 472 | 473 | @-moz-keyframes prism-previewer-time { 474 | 0% { 475 | stroke-dasharray: 0, 500; 476 | stroke-dashoffset: 0; 477 | } 478 | 50% { 479 | stroke-dasharray: 100, 500; 480 | stroke-dashoffset: 0; 481 | } 482 | 100% { 483 | stroke-dasharray: 0, 500; 484 | stroke-dashoffset: -100; 485 | } 486 | } 487 | 488 | @keyframes prism-previewer-time { 489 | 0% { 490 | stroke-dasharray: 0, 500; 491 | stroke-dashoffset: 0; 492 | } 493 | 50% { 494 | stroke-dasharray: 100, 500; 495 | stroke-dashoffset: 0; 496 | } 497 | 100% { 498 | stroke-dasharray: 0, 500; 499 | stroke-dashoffset: -100; 500 | } 501 | } 502 | 503 | .prism-previewer-time:before { 504 | border-radius: 50%; 505 | background: #fff; 506 | } 507 | .prism-previewer-time:after { 508 | margin-top: 4px; 509 | } 510 | .prism-previewer-time svg { 511 | width: 32px; 512 | height: 32px; 513 | -webkit-transform: rotate(-90deg); 514 | -moz-transform: rotate(-90deg); 515 | -ms-transform: rotate(-90deg); 516 | -o-transform: rotate(-90deg); 517 | transform: rotate(-90deg); 518 | } 519 | .prism-previewer-time circle { 520 | fill: transparent; 521 | stroke: hsl(200, 10%, 20%); 522 | stroke-opacity: 0.9; 523 | stroke-width: 32; 524 | stroke-dasharray: 0, 500; 525 | stroke-dashoffset: 0; 526 | -webkit-animation: prism-previewer-time linear infinite 3s; 527 | -moz-animation: prism-previewer-time linear infinite 3s; 528 | -o-animation: prism-previewer-time linear infinite 3s; 529 | animation: prism-previewer-time linear infinite 3s; 530 | } 531 | .prism-previewer-angle:before { 532 | border-radius: 50%; 533 | background: #fff; 534 | } 535 | .prism-previewer-angle:after { 536 | margin-top: 4px; 537 | } 538 | .prism-previewer-angle svg { 539 | width: 32px; 540 | height: 32px; 541 | -webkit-transform: rotate(-90deg); 542 | -moz-transform: rotate(-90deg); 543 | -ms-transform: rotate(-90deg); 544 | -o-transform: rotate(-90deg); 545 | transform: rotate(-90deg); 546 | } 547 | .prism-previewer-angle[data-negative] svg { 548 | -webkit-transform: scaleX(-1) rotate(-90deg); 549 | -moz-transform: scaleX(-1) rotate(-90deg); 550 | -ms-transform: scaleX(-1) rotate(-90deg); 551 | -o-transform: scaleX(-1) rotate(-90deg); 552 | transform: scaleX(-1) rotate(-90deg); 553 | } 554 | .prism-previewer-angle circle { 555 | fill: transparent; 556 | stroke: hsl(200, 10%, 20%); 557 | stroke-opacity: 0.9; 558 | stroke-width: 32; 559 | stroke-dasharray: 0, 500; 560 | } 561 | /* Fallback, in case JS does not run, to ensure the code is at least visible */ 562 | .lang-markup script[type='text/plain'], 563 | .language-markup script[type='text/plain'], 564 | script[type='text/plain'].lang-markup, 565 | script[type='text/plain'].language-markup { 566 | display: block; 567 | font: 100% Consolas, Monaco, monospace; 568 | white-space: pre; 569 | overflow: auto; 570 | } 571 | 572 | .command-line-prompt { 573 | border-right: 1px solid #999; 574 | display: block; 575 | float: left; 576 | font-size: 100%; 577 | letter-spacing: -1px; 578 | margin-right: 1em; 579 | pointer-events: none; 580 | 581 | -webkit-user-select: none; 582 | -moz-user-select: none; 583 | -ms-user-select: none; 584 | user-select: none; 585 | } 586 | 587 | .command-line-prompt > span:before { 588 | color: #999; 589 | content: ' '; 590 | display: block; 591 | padding-right: 0.8em; 592 | } 593 | 594 | .command-line-prompt > span[data-user]:before { 595 | content: "[" attr(data-user) "@" attr(data-host) "] $"; 596 | } 597 | 598 | .command-line-prompt > span[data-user="root"]:before { 599 | content: "[" attr(data-user) "@" attr(data-host) "] #"; 600 | } 601 | 602 | .command-line-prompt > span[data-prompt]:before { 603 | content: attr(data-prompt); 604 | } 605 | 606 | -------------------------------------------------------------------------------- /docs/templates/docs/index.html: -------------------------------------------------------------------------------- 1 | {% extends "_base.html" %} 2 | {% load i18n %} 3 | {% load staticfiles %} 4 | {% get_current_language as LANGUAGE_CODE %} 5 | {% get_language_info for LANGUAGE_CODE as lang %} 6 | {% get_available_languages as LANGUAGES %} 7 | {% get_current_language_bidi as RTL %} 8 | {% block title %} 9 | {% trans "Quran Tafseer API - Documentation" %} 10 | {% endblock %} 11 | {% block style %} 12 | 13 | {% endblock %} 14 | {% block container %} 15 |
16 |
17 |

{% trans "Quran Tafseer" %}

18 |

19 | {% blocktrans %}Main Description{% endblocktrans %} 20 |

21 |
22 |
23 |
24 | 36 |
37 |
38 |
39 |
40 |

{% trans "Chapter List Endpoint" %}

41 |
42 |
43 |
44 |

{% trans "Description" %}

45 | {% blocktrans %}Simple API endpoint to get a list of Quran chapters, the index can be use in other endpoints.{% endblocktrans %} 46 |
47 |
48 |

{% trans "Request" %}

49 |
50 |
51 |
52 | HTTP Method 53 |
54 |
55 | GET 56 |
57 |
58 |
59 |
60 | URL 61 |
62 |
63 | 64 | api.quran-tafseer.com/quran 65 | 66 |
67 |
68 |
69 |
70 | URL Parameters 71 |
72 |
73 | None 74 |
75 |
76 |
77 |

{% trans "Response" %}

78 |
79 |
80 |
81 | {% trans "Status Codes" %} 82 |
83 |
84 |
85 |
86 |
    87 |
  • 200 OK: Returned list of Quran's chapters
  • 88 |
89 |
90 |
91 |
92 |
93 | {% trans "Body" %} 94 |
95 |
96 |
97 |
98 |
 99 |                         
100 | [
101 |     {
102 |         "index": 1,
103 |         "name": "الفاتحة"
104 |     },
105 |     {
106 |         "index": 2,
107 |         "name": "البقرة"
108 |     },
109 |     {
110 |         "index": 3,
111 |         "name": "آل عمران"
112 |     },
113 |     ...
114 | ]
115 |                         
116 |                     
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |

{% trans "Verse Details Endpoint" %}

125 |
126 |
127 |
128 |

{% trans "Description" %}

129 | {% blocktrans %}API endpoint to get a text for specific Verse in Sura, you should pass Sura number and Ayah number as URL path parameter.{% endblocktrans %} 130 |
131 |
132 |

{% trans "Request" %}

133 |
134 |
135 |
136 | HTTP Method 137 |
138 |
139 | GET 140 |
141 |
142 |
143 |
144 | URL 145 |
146 | 151 |
152 |
153 |
154 | URL Parameters 155 |
156 |
157 |
    158 |
  • sura_number: Chapter Number
  • 159 |
  • ayah_number: Verse Number
  • 160 |
161 |
162 |
163 |
164 |

{% trans "Response" %}

165 |
166 |
167 |
168 | {% trans "Status Codes" %} 169 |
170 | 171 |
172 |
173 |
174 |
    175 |
  • 200 OK: Returned details of Qura'sn verse
  • 176 |
  • 404 Not Found: Can't found verse with supplied sura_number and ayah_number
  • 177 | 178 |
179 |
180 |
181 |
182 |
183 | {% trans "Body" %} 184 |
185 |
186 |
187 |
188 |
189 |                     
190 | {
191 |     "sura_index": 1,
192 |     "sura_name": "الفاتحة",
193 |     "ayah_number": 1,
194 |     "text": "بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ"
195 | }
196 |                     
197 |                 
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |

{% trans "Tafseer List Endpoint" %}

206 |
207 |
208 |
209 |

{% trans "Description" %}

210 | {% blocktrans %}Simple API endpoint to get a list of Quran tafseer available in Tafseer API, the id can be use in other endpoints.{% endblocktrans %} 211 |
212 |
213 |

{% trans "Request" %}

214 |
215 |
216 |
217 | HTTP Method 218 |
219 |
220 | GET 221 |
222 |
223 |
224 |
225 | URL 226 |
227 |
228 | 229 | api.quran-tafseer.com/tafseer 230 | 231 |
232 |
233 |
234 |
235 | URL Parameters 236 |
237 |
238 | None 239 |
240 |
241 |
242 |

{% trans "Response" %}

243 |
244 |
245 |
246 | {% trans "Status Codes" %} 247 |
248 |
249 |
250 |
251 |
    252 |
  • 200 OK: Returned list of Quran's tafseers
  • 253 |
254 |
255 |
256 |
257 |
258 | {% trans "Body" %} 259 |
260 |
261 |
262 |                     
263 | [
264 |     {
265 |         "id": 1,
266 |         "name": "التفسير الميسر",
267 |         "language": "ar",
268 |         "author": "نخبة من العلماء",
269 |         "book_name": "التفسير الميسر"
270 |     },
271 |     {
272 |         "id": 2,
273 |         "name": "تفسير الجلالين",
274 |         "language": "ar",
275 |         "author": "جلال الدين المحلي و السيوطي",
276 |         "book_name": "تفسير الجلالين"
277 |     },
278 |     ...
279 | ]
280 |                     
281 |                 
282 |
283 |
284 |
285 |
286 |
287 |
288 |

{% trans "Verse Tafseer Endpoint" %}

289 |
290 |
291 |
292 |

{% trans "Description" %}

293 | {% blocktrans %}API endpoint to get a specific tasfeer for verse in chapter, you should pass Tafseer Id which can get from Tafseer List Endpoint, Sura number, and Ayah number as URL path parameter.{% endblocktrans %} 294 |
295 |
296 |

{% trans "Request" %}

297 |
298 |
299 |
300 | HTTP Method 301 |
302 |
303 | GET 304 |
305 |
306 |
307 |
308 | URL 309 |
310 | 315 |
316 |
317 |
318 | URL Parameters 319 |
320 |
321 |
    322 |
  • tafseer_id: Tafseer Id
  • 323 |
  • sura_number: Chapter Number
  • 324 |
  • ayah_number: Verse Number
  • 325 |
326 |
327 |
328 |
329 |

{% trans "Response" %}

330 |
331 |
332 |
333 | {% trans "Status Codes" %} 334 |
335 | 336 |
337 |
338 |
339 |
    340 |
  • 200 OK: Returned list of Quran verse's tafseer
  • 341 |
  • 404 NOT FOUND: Can't find tafseer with id supplied or with chapter number and verse number
  • 342 |
343 |
344 |
345 |
346 |
347 | {% trans "Body" %} 348 |
349 |
350 |
351 |
352 |                     
353 | {
354 |     "tafseer_id": 1,
355 |     "tafseer_name": "التفسير الميسر",
356 |     "ayah_url": "/quran/2/1",
357 |     "ayah_number": 8,
358 |     "text": "هذه الحروف وغيرها من الحروف المقطَّعة في أوائل السور فيها إشارة إلى إعجاز القرآن؛ فقد وقع به تحدي المشركين، فعجزوا عن معارضته، وهو مركَّب من هذه الحروف التي تتكون منها لغة العرب. فدَلَّ عجز العرب عن الإتيان بمثله -مع أنهم أفصح الناس- على أن القرآن وحي من الله."
359 | }
360 |                     
361 |                 
362 |
363 |
364 |
365 |
366 |
367 |
368 |

{% trans "Verse Tafseer Range Endpoint" %}

369 |
370 |
371 |
372 |

{% trans "Description" %}

373 | {% blocktrans %}API endpoint to get a specific tasfeer for range of verses in a chapter, you should pass Tafseer Id which can get from Tafseer List Endpoint, Sura number, Ayah number from, and Ayah number to as URL path parameter.{% endblocktrans %} 374 |
375 |
376 |

{% trans "Request" %}

377 |
378 |
379 |
380 | HTTP Method 381 |
382 |
383 | GET 384 |
385 |
386 | 396 |
397 |
398 | URL Parameters 399 |
400 |
401 |
    402 |
  • tafseer_id: Tafseer Id
  • 403 |
  • sura_number: Chapter Number
  • 404 |
  • ayah_number_from: Start Verse Number Range
  • 405 |
  • ayah_number_to: End Verse Number Range
  • 406 |
407 |
408 |
409 |
410 |

{% trans "Response" %}

411 |
412 |
413 |
414 | {% trans "Status Codes" %} 415 |
416 |
417 |
418 |
419 |
    420 |
  • 200 OK: Returned list of Quran's verses tafseer according to the range
  • 421 |
  • 404 NOT FOUND: 422 |
      423 |
    • Can't find tafseer with id supplied or with chapter number and verse number range.
    • 424 |
    • Wrong Verse numbers range (Replace start index with the end index).
    • 425 |
    426 | 427 |
428 |
429 |
430 |
431 |
432 | {% trans "Body" %} 433 |
434 |
435 |
436 |
437 |                     
438 | [
439 |     {
440 |         "tafseer_id": 1,
441 |         "tafseer_name": "التفسير الميسر",
442 |         "ayah_url": "/quran/1/1",
443 |         "ayah_number": 1,
444 |         "text": "سورة الفاتحة سميت هذه السورة بالفاتحة؛ لأنه يفتتح بها القرآن العظيم، وتسمى المثاني؛ لأنها تقرأ في كل ركعة، ولها أسماء أخر. أبتدئ قراءة القرآن باسم الله مستعينا به، (اللهِ) علم على الرب -تبارك وتعالى- المعبود بحق دون سواه، وهو أخص أسماء الله تعالى، ولا يسمى به غيره سبحانه. (الرَّحْمَنِ) ذي الرحمة العامة الذي وسعت رحمته جميع الخلق، (الرَّحِيمِ) بالمؤمنين، وهما اسمان من أسمائه تعالى، يتضمنان إثبات صفة الرحمة لله تعالى كما يليق بجلاله."
445 |     },
446 |     {
447 |         "tafseer_id": 1,
448 |         "tafseer_name": "التفسير الميسر",
449 |         "ayah_url": "/quran/1/2",
450 |         "ayah_number": 2,
451 |         "text": "(الحَمْدُ للهِ رَبِّ العَالَمِينَ) الثناء على الله بصفاته التي كلُّها أوصاف كمال، وبنعمه الظاهرة والباطنة، الدينية والدنيوية، وفي ضمنه أَمْرٌ لعباده أن يحمدوه، فهو المستحق له وحده، وهو سبحانه المنشئ للخلق، القائم بأمورهم، المربي لجميع خلقه بنعمه، ولأوليائه بالإيمان والعمل الصالح."
452 |     },
453 |     {
454 |         "tafseer_id": 1,
455 |         "tafseer_name": "التفسير الميسر",
456 |         "ayah_url": "/quran/1/3",
457 |         "ayah_number": 3,
458 |         "text": "(الرَّحْمَنِ) الذي وسعت رحمته جميع الخلق، (الرَّحِيمِ)، بالمؤمنين، وهما اسمان من أسماء الله تعالى."
459 |     },
460 |     {
461 |         "tafseer_id": 1,
462 |         "tafseer_name": "التفسير الميسر",
463 |         "ayah_url": "/quran/1/4",
464 |         "ayah_number": 4,
465 |         "text": "وهو سبحانه وحده مالك يوم القيامة، وهو يوم الجزاء على الأعمال. وفي قراءة المسلم لهذه الآية في كل ركعة من صلواته تذكير له باليوم الآخر، وحثٌّ له على الاستعداد بالعمل الصالح، والكف عن المعاصي والسيئات."
466 |     },
467 |     {
468 |         "tafseer_id": 1,
469 |         "tafseer_name": "التفسير الميسر",
470 |         "ayah_url": "/quran/1/5",
471 |         "ayah_number": 5,
472 |         "text": "إنا نخصك وحدك بالعبادة، ونستعين بك وحدك في جميع أمورنا، فالأمر كله بيدك، لا يملك منه أحد مثقال ذرة. وفي هذه الآية دليل على أن العبد لا يجوز له أن يصرف شيئًا من أنواع العبادة كالدعاء والاستغاثة والذبح والطواف إلا لله وحده، وفيها شفاء القلوب من داء التعلق بغير الله، ومن أمراض الرياء والعجب، والكبرياء."
473 |     },
474 |     {
475 |         "tafseer_id": 1,
476 |         "tafseer_name": "التفسير الميسر",
477 |         "ayah_url": "/quran/1/6",
478 |         "ayah_number": 6,
479 |         "text": "دُلَّنا، وأرشدنا، ووفقنا إلى الطريق المستقيم، وثبتنا عليه حتى نلقاك، وهو الإسلام، الذي هو الطريق الواضح الموصل إلى رضوان الله وإلى جنته، الذي دلّ عليه خاتم رسله وأنبيائه محمد صلى الله عليه وسلم، فلا سبيل إلى سعادة العبد إلا بالاستقامة عليه."
480 |     }
481 | ]                    
482 |                 
483 |
484 |
485 |
486 |
487 | {% endblock %} 488 | {% block scripts %} 489 | 490 | {% endblock %} 491 | -------------------------------------------------------------------------------- /static/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.6 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.6",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.6",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.6",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.6",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.6",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); -------------------------------------------------------------------------------- /static/css/bootstrap-rtl.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * bootstrap-rtl (version 3.3.4) 3 | * Author: Morteza Ansarinia (http://github.com/morteza) 4 | * Created on: August 13,2015 5 | * Project: bootstrap-rtl 6 | * Copyright: Unlicensed Public Domain 7 | *******************************************************************************/ 8 | 9 | html { 10 | direction: rtl; 11 | } 12 | body { 13 | direction: rtl; 14 | } 15 | .flip.text-left { 16 | text-align: right; 17 | } 18 | .flip.text-right { 19 | text-align: left; 20 | } 21 | .list-unstyled { 22 | padding-right: 0; 23 | padding-left: initial; 24 | } 25 | .list-inline { 26 | padding-right: 0; 27 | padding-left: initial; 28 | margin-right: -5px; 29 | margin-left: 0; 30 | } 31 | dd { 32 | margin-right: 0; 33 | margin-left: initial; 34 | } 35 | @media (min-width: 768px) { 36 | .dl-horizontal dt { 37 | float: right; 38 | clear: right; 39 | text-align: left; 40 | } 41 | .dl-horizontal dd { 42 | margin-right: 180px; 43 | margin-left: 0; 44 | } 45 | } 46 | blockquote { 47 | border-right: 5px solid #eeeeee; 48 | border-left: 0; 49 | } 50 | .blockquote-reverse, 51 | blockquote.pull-left { 52 | padding-left: 15px; 53 | padding-right: 0; 54 | border-left: 5px solid #eeeeee; 55 | border-right: 0; 56 | text-align: left; 57 | } 58 | .col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { 59 | position: relative; 60 | min-height: 1px; 61 | padding-left: 15px; 62 | padding-right: 15px; 63 | } 64 | .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { 65 | float: right; 66 | } 67 | .col-xs-12 { 68 | width: 100%; 69 | } 70 | .col-xs-11 { 71 | width: 91.66666667%; 72 | } 73 | .col-xs-10 { 74 | width: 83.33333333%; 75 | } 76 | .col-xs-9 { 77 | width: 75%; 78 | } 79 | .col-xs-8 { 80 | width: 66.66666667%; 81 | } 82 | .col-xs-7 { 83 | width: 58.33333333%; 84 | } 85 | .col-xs-6 { 86 | width: 50%; 87 | } 88 | .col-xs-5 { 89 | width: 41.66666667%; 90 | } 91 | .col-xs-4 { 92 | width: 33.33333333%; 93 | } 94 | .col-xs-3 { 95 | width: 25%; 96 | } 97 | .col-xs-2 { 98 | width: 16.66666667%; 99 | } 100 | .col-xs-1 { 101 | width: 8.33333333%; 102 | } 103 | .col-xs-pull-12 { 104 | left: 100%; 105 | right: auto; 106 | } 107 | .col-xs-pull-11 { 108 | left: 91.66666667%; 109 | right: auto; 110 | } 111 | .col-xs-pull-10 { 112 | left: 83.33333333%; 113 | right: auto; 114 | } 115 | .col-xs-pull-9 { 116 | left: 75%; 117 | right: auto; 118 | } 119 | .col-xs-pull-8 { 120 | left: 66.66666667%; 121 | right: auto; 122 | } 123 | .col-xs-pull-7 { 124 | left: 58.33333333%; 125 | right: auto; 126 | } 127 | .col-xs-pull-6 { 128 | left: 50%; 129 | right: auto; 130 | } 131 | .col-xs-pull-5 { 132 | left: 41.66666667%; 133 | right: auto; 134 | } 135 | .col-xs-pull-4 { 136 | left: 33.33333333%; 137 | right: auto; 138 | } 139 | .col-xs-pull-3 { 140 | left: 25%; 141 | right: auto; 142 | } 143 | .col-xs-pull-2 { 144 | left: 16.66666667%; 145 | right: auto; 146 | } 147 | .col-xs-pull-1 { 148 | left: 8.33333333%; 149 | right: auto; 150 | } 151 | .col-xs-pull-0 { 152 | left: auto; 153 | right: auto; 154 | } 155 | .col-xs-push-12 { 156 | right: 100%; 157 | left: 0; 158 | } 159 | .col-xs-push-11 { 160 | right: 91.66666667%; 161 | left: 0; 162 | } 163 | .col-xs-push-10 { 164 | right: 83.33333333%; 165 | left: 0; 166 | } 167 | .col-xs-push-9 { 168 | right: 75%; 169 | left: 0; 170 | } 171 | .col-xs-push-8 { 172 | right: 66.66666667%; 173 | left: 0; 174 | } 175 | .col-xs-push-7 { 176 | right: 58.33333333%; 177 | left: 0; 178 | } 179 | .col-xs-push-6 { 180 | right: 50%; 181 | left: 0; 182 | } 183 | .col-xs-push-5 { 184 | right: 41.66666667%; 185 | left: 0; 186 | } 187 | .col-xs-push-4 { 188 | right: 33.33333333%; 189 | left: 0; 190 | } 191 | .col-xs-push-3 { 192 | right: 25%; 193 | left: 0; 194 | } 195 | .col-xs-push-2 { 196 | right: 16.66666667%; 197 | left: 0; 198 | } 199 | .col-xs-push-1 { 200 | right: 8.33333333%; 201 | left: 0; 202 | } 203 | .col-xs-push-0 { 204 | right: auto; 205 | left: 0; 206 | } 207 | .col-xs-offset-12 { 208 | margin-right: 100%; 209 | margin-left: 0; 210 | } 211 | .col-xs-offset-11 { 212 | margin-right: 91.66666667%; 213 | margin-left: 0; 214 | } 215 | .col-xs-offset-10 { 216 | margin-right: 83.33333333%; 217 | margin-left: 0; 218 | } 219 | .col-xs-offset-9 { 220 | margin-right: 75%; 221 | margin-left: 0; 222 | } 223 | .col-xs-offset-8 { 224 | margin-right: 66.66666667%; 225 | margin-left: 0; 226 | } 227 | .col-xs-offset-7 { 228 | margin-right: 58.33333333%; 229 | margin-left: 0; 230 | } 231 | .col-xs-offset-6 { 232 | margin-right: 50%; 233 | margin-left: 0; 234 | } 235 | .col-xs-offset-5 { 236 | margin-right: 41.66666667%; 237 | margin-left: 0; 238 | } 239 | .col-xs-offset-4 { 240 | margin-right: 33.33333333%; 241 | margin-left: 0; 242 | } 243 | .col-xs-offset-3 { 244 | margin-right: 25%; 245 | margin-left: 0; 246 | } 247 | .col-xs-offset-2 { 248 | margin-right: 16.66666667%; 249 | margin-left: 0; 250 | } 251 | .col-xs-offset-1 { 252 | margin-right: 8.33333333%; 253 | margin-left: 0; 254 | } 255 | .col-xs-offset-0 { 256 | margin-right: 0%; 257 | margin-left: 0; 258 | } 259 | @media (min-width: 768px) { 260 | .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { 261 | float: right; 262 | } 263 | .col-sm-12 { 264 | width: 100%; 265 | } 266 | .col-sm-11 { 267 | width: 91.66666667%; 268 | } 269 | .col-sm-10 { 270 | width: 83.33333333%; 271 | } 272 | .col-sm-9 { 273 | width: 75%; 274 | } 275 | .col-sm-8 { 276 | width: 66.66666667%; 277 | } 278 | .col-sm-7 { 279 | width: 58.33333333%; 280 | } 281 | .col-sm-6 { 282 | width: 50%; 283 | } 284 | .col-sm-5 { 285 | width: 41.66666667%; 286 | } 287 | .col-sm-4 { 288 | width: 33.33333333%; 289 | } 290 | .col-sm-3 { 291 | width: 25%; 292 | } 293 | .col-sm-2 { 294 | width: 16.66666667%; 295 | } 296 | .col-sm-1 { 297 | width: 8.33333333%; 298 | } 299 | .col-sm-pull-12 { 300 | left: 100%; 301 | right: auto; 302 | } 303 | .col-sm-pull-11 { 304 | left: 91.66666667%; 305 | right: auto; 306 | } 307 | .col-sm-pull-10 { 308 | left: 83.33333333%; 309 | right: auto; 310 | } 311 | .col-sm-pull-9 { 312 | left: 75%; 313 | right: auto; 314 | } 315 | .col-sm-pull-8 { 316 | left: 66.66666667%; 317 | right: auto; 318 | } 319 | .col-sm-pull-7 { 320 | left: 58.33333333%; 321 | right: auto; 322 | } 323 | .col-sm-pull-6 { 324 | left: 50%; 325 | right: auto; 326 | } 327 | .col-sm-pull-5 { 328 | left: 41.66666667%; 329 | right: auto; 330 | } 331 | .col-sm-pull-4 { 332 | left: 33.33333333%; 333 | right: auto; 334 | } 335 | .col-sm-pull-3 { 336 | left: 25%; 337 | right: auto; 338 | } 339 | .col-sm-pull-2 { 340 | left: 16.66666667%; 341 | right: auto; 342 | } 343 | .col-sm-pull-1 { 344 | left: 8.33333333%; 345 | right: auto; 346 | } 347 | .col-sm-pull-0 { 348 | left: auto; 349 | right: auto; 350 | } 351 | .col-sm-push-12 { 352 | right: 100%; 353 | left: 0; 354 | } 355 | .col-sm-push-11 { 356 | right: 91.66666667%; 357 | left: 0; 358 | } 359 | .col-sm-push-10 { 360 | right: 83.33333333%; 361 | left: 0; 362 | } 363 | .col-sm-push-9 { 364 | right: 75%; 365 | left: 0; 366 | } 367 | .col-sm-push-8 { 368 | right: 66.66666667%; 369 | left: 0; 370 | } 371 | .col-sm-push-7 { 372 | right: 58.33333333%; 373 | left: 0; 374 | } 375 | .col-sm-push-6 { 376 | right: 50%; 377 | left: 0; 378 | } 379 | .col-sm-push-5 { 380 | right: 41.66666667%; 381 | left: 0; 382 | } 383 | .col-sm-push-4 { 384 | right: 33.33333333%; 385 | left: 0; 386 | } 387 | .col-sm-push-3 { 388 | right: 25%; 389 | left: 0; 390 | } 391 | .col-sm-push-2 { 392 | right: 16.66666667%; 393 | left: 0; 394 | } 395 | .col-sm-push-1 { 396 | right: 8.33333333%; 397 | left: 0; 398 | } 399 | .col-sm-push-0 { 400 | right: auto; 401 | left: 0; 402 | } 403 | .col-sm-offset-12 { 404 | margin-right: 100%; 405 | margin-left: 0; 406 | } 407 | .col-sm-offset-11 { 408 | margin-right: 91.66666667%; 409 | margin-left: 0; 410 | } 411 | .col-sm-offset-10 { 412 | margin-right: 83.33333333%; 413 | margin-left: 0; 414 | } 415 | .col-sm-offset-9 { 416 | margin-right: 75%; 417 | margin-left: 0; 418 | } 419 | .col-sm-offset-8 { 420 | margin-right: 66.66666667%; 421 | margin-left: 0; 422 | } 423 | .col-sm-offset-7 { 424 | margin-right: 58.33333333%; 425 | margin-left: 0; 426 | } 427 | .col-sm-offset-6 { 428 | margin-right: 50%; 429 | margin-left: 0; 430 | } 431 | .col-sm-offset-5 { 432 | margin-right: 41.66666667%; 433 | margin-left: 0; 434 | } 435 | .col-sm-offset-4 { 436 | margin-right: 33.33333333%; 437 | margin-left: 0; 438 | } 439 | .col-sm-offset-3 { 440 | margin-right: 25%; 441 | margin-left: 0; 442 | } 443 | .col-sm-offset-2 { 444 | margin-right: 16.66666667%; 445 | margin-left: 0; 446 | } 447 | .col-sm-offset-1 { 448 | margin-right: 8.33333333%; 449 | margin-left: 0; 450 | } 451 | .col-sm-offset-0 { 452 | margin-right: 0%; 453 | margin-left: 0; 454 | } 455 | } 456 | @media (min-width: 992px) { 457 | .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { 458 | float: right; 459 | } 460 | .col-md-12 { 461 | width: 100%; 462 | } 463 | .col-md-11 { 464 | width: 91.66666667%; 465 | } 466 | .col-md-10 { 467 | width: 83.33333333%; 468 | } 469 | .col-md-9 { 470 | width: 75%; 471 | } 472 | .col-md-8 { 473 | width: 66.66666667%; 474 | } 475 | .col-md-7 { 476 | width: 58.33333333%; 477 | } 478 | .col-md-6 { 479 | width: 50%; 480 | } 481 | .col-md-5 { 482 | width: 41.66666667%; 483 | } 484 | .col-md-4 { 485 | width: 33.33333333%; 486 | } 487 | .col-md-3 { 488 | width: 25%; 489 | } 490 | .col-md-2 { 491 | width: 16.66666667%; 492 | } 493 | .col-md-1 { 494 | width: 8.33333333%; 495 | } 496 | .col-md-pull-12 { 497 | left: 100%; 498 | right: auto; 499 | } 500 | .col-md-pull-11 { 501 | left: 91.66666667%; 502 | right: auto; 503 | } 504 | .col-md-pull-10 { 505 | left: 83.33333333%; 506 | right: auto; 507 | } 508 | .col-md-pull-9 { 509 | left: 75%; 510 | right: auto; 511 | } 512 | .col-md-pull-8 { 513 | left: 66.66666667%; 514 | right: auto; 515 | } 516 | .col-md-pull-7 { 517 | left: 58.33333333%; 518 | right: auto; 519 | } 520 | .col-md-pull-6 { 521 | left: 50%; 522 | right: auto; 523 | } 524 | .col-md-pull-5 { 525 | left: 41.66666667%; 526 | right: auto; 527 | } 528 | .col-md-pull-4 { 529 | left: 33.33333333%; 530 | right: auto; 531 | } 532 | .col-md-pull-3 { 533 | left: 25%; 534 | right: auto; 535 | } 536 | .col-md-pull-2 { 537 | left: 16.66666667%; 538 | right: auto; 539 | } 540 | .col-md-pull-1 { 541 | left: 8.33333333%; 542 | right: auto; 543 | } 544 | .col-md-pull-0 { 545 | left: auto; 546 | right: auto; 547 | } 548 | .col-md-push-12 { 549 | right: 100%; 550 | left: 0; 551 | } 552 | .col-md-push-11 { 553 | right: 91.66666667%; 554 | left: 0; 555 | } 556 | .col-md-push-10 { 557 | right: 83.33333333%; 558 | left: 0; 559 | } 560 | .col-md-push-9 { 561 | right: 75%; 562 | left: 0; 563 | } 564 | .col-md-push-8 { 565 | right: 66.66666667%; 566 | left: 0; 567 | } 568 | .col-md-push-7 { 569 | right: 58.33333333%; 570 | left: 0; 571 | } 572 | .col-md-push-6 { 573 | right: 50%; 574 | left: 0; 575 | } 576 | .col-md-push-5 { 577 | right: 41.66666667%; 578 | left: 0; 579 | } 580 | .col-md-push-4 { 581 | right: 33.33333333%; 582 | left: 0; 583 | } 584 | .col-md-push-3 { 585 | right: 25%; 586 | left: 0; 587 | } 588 | .col-md-push-2 { 589 | right: 16.66666667%; 590 | left: 0; 591 | } 592 | .col-md-push-1 { 593 | right: 8.33333333%; 594 | left: 0; 595 | } 596 | .col-md-push-0 { 597 | right: auto; 598 | left: 0; 599 | } 600 | .col-md-offset-12 { 601 | margin-right: 100%; 602 | margin-left: 0; 603 | } 604 | .col-md-offset-11 { 605 | margin-right: 91.66666667%; 606 | margin-left: 0; 607 | } 608 | .col-md-offset-10 { 609 | margin-right: 83.33333333%; 610 | margin-left: 0; 611 | } 612 | .col-md-offset-9 { 613 | margin-right: 75%; 614 | margin-left: 0; 615 | } 616 | .col-md-offset-8 { 617 | margin-right: 66.66666667%; 618 | margin-left: 0; 619 | } 620 | .col-md-offset-7 { 621 | margin-right: 58.33333333%; 622 | margin-left: 0; 623 | } 624 | .col-md-offset-6 { 625 | margin-right: 50%; 626 | margin-left: 0; 627 | } 628 | .col-md-offset-5 { 629 | margin-right: 41.66666667%; 630 | margin-left: 0; 631 | } 632 | .col-md-offset-4 { 633 | margin-right: 33.33333333%; 634 | margin-left: 0; 635 | } 636 | .col-md-offset-3 { 637 | margin-right: 25%; 638 | margin-left: 0; 639 | } 640 | .col-md-offset-2 { 641 | margin-right: 16.66666667%; 642 | margin-left: 0; 643 | } 644 | .col-md-offset-1 { 645 | margin-right: 8.33333333%; 646 | margin-left: 0; 647 | } 648 | .col-md-offset-0 { 649 | margin-right: 0%; 650 | margin-left: 0; 651 | } 652 | } 653 | @media (min-width: 1200px) { 654 | .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { 655 | float: right; 656 | } 657 | .col-lg-12 { 658 | width: 100%; 659 | } 660 | .col-lg-11 { 661 | width: 91.66666667%; 662 | } 663 | .col-lg-10 { 664 | width: 83.33333333%; 665 | } 666 | .col-lg-9 { 667 | width: 75%; 668 | } 669 | .col-lg-8 { 670 | width: 66.66666667%; 671 | } 672 | .col-lg-7 { 673 | width: 58.33333333%; 674 | } 675 | .col-lg-6 { 676 | width: 50%; 677 | } 678 | .col-lg-5 { 679 | width: 41.66666667%; 680 | } 681 | .col-lg-4 { 682 | width: 33.33333333%; 683 | } 684 | .col-lg-3 { 685 | width: 25%; 686 | } 687 | .col-lg-2 { 688 | width: 16.66666667%; 689 | } 690 | .col-lg-1 { 691 | width: 8.33333333%; 692 | } 693 | .col-lg-pull-12 { 694 | left: 100%; 695 | right: auto; 696 | } 697 | .col-lg-pull-11 { 698 | left: 91.66666667%; 699 | right: auto; 700 | } 701 | .col-lg-pull-10 { 702 | left: 83.33333333%; 703 | right: auto; 704 | } 705 | .col-lg-pull-9 { 706 | left: 75%; 707 | right: auto; 708 | } 709 | .col-lg-pull-8 { 710 | left: 66.66666667%; 711 | right: auto; 712 | } 713 | .col-lg-pull-7 { 714 | left: 58.33333333%; 715 | right: auto; 716 | } 717 | .col-lg-pull-6 { 718 | left: 50%; 719 | right: auto; 720 | } 721 | .col-lg-pull-5 { 722 | left: 41.66666667%; 723 | right: auto; 724 | } 725 | .col-lg-pull-4 { 726 | left: 33.33333333%; 727 | right: auto; 728 | } 729 | .col-lg-pull-3 { 730 | left: 25%; 731 | right: auto; 732 | } 733 | .col-lg-pull-2 { 734 | left: 16.66666667%; 735 | right: auto; 736 | } 737 | .col-lg-pull-1 { 738 | left: 8.33333333%; 739 | right: auto; 740 | } 741 | .col-lg-pull-0 { 742 | left: auto; 743 | right: auto; 744 | } 745 | .col-lg-push-12 { 746 | right: 100%; 747 | left: 0; 748 | } 749 | .col-lg-push-11 { 750 | right: 91.66666667%; 751 | left: 0; 752 | } 753 | .col-lg-push-10 { 754 | right: 83.33333333%; 755 | left: 0; 756 | } 757 | .col-lg-push-9 { 758 | right: 75%; 759 | left: 0; 760 | } 761 | .col-lg-push-8 { 762 | right: 66.66666667%; 763 | left: 0; 764 | } 765 | .col-lg-push-7 { 766 | right: 58.33333333%; 767 | left: 0; 768 | } 769 | .col-lg-push-6 { 770 | right: 50%; 771 | left: 0; 772 | } 773 | .col-lg-push-5 { 774 | right: 41.66666667%; 775 | left: 0; 776 | } 777 | .col-lg-push-4 { 778 | right: 33.33333333%; 779 | left: 0; 780 | } 781 | .col-lg-push-3 { 782 | right: 25%; 783 | left: 0; 784 | } 785 | .col-lg-push-2 { 786 | right: 16.66666667%; 787 | left: 0; 788 | } 789 | .col-lg-push-1 { 790 | right: 8.33333333%; 791 | left: 0; 792 | } 793 | .col-lg-push-0 { 794 | right: auto; 795 | left: 0; 796 | } 797 | .col-lg-offset-12 { 798 | margin-right: 100%; 799 | margin-left: 0; 800 | } 801 | .col-lg-offset-11 { 802 | margin-right: 91.66666667%; 803 | margin-left: 0; 804 | } 805 | .col-lg-offset-10 { 806 | margin-right: 83.33333333%; 807 | margin-left: 0; 808 | } 809 | .col-lg-offset-9 { 810 | margin-right: 75%; 811 | margin-left: 0; 812 | } 813 | .col-lg-offset-8 { 814 | margin-right: 66.66666667%; 815 | margin-left: 0; 816 | } 817 | .col-lg-offset-7 { 818 | margin-right: 58.33333333%; 819 | margin-left: 0; 820 | } 821 | .col-lg-offset-6 { 822 | margin-right: 50%; 823 | margin-left: 0; 824 | } 825 | .col-lg-offset-5 { 826 | margin-right: 41.66666667%; 827 | margin-left: 0; 828 | } 829 | .col-lg-offset-4 { 830 | margin-right: 33.33333333%; 831 | margin-left: 0; 832 | } 833 | .col-lg-offset-3 { 834 | margin-right: 25%; 835 | margin-left: 0; 836 | } 837 | .col-lg-offset-2 { 838 | margin-right: 16.66666667%; 839 | margin-left: 0; 840 | } 841 | .col-lg-offset-1 { 842 | margin-right: 8.33333333%; 843 | margin-left: 0; 844 | } 845 | .col-lg-offset-0 { 846 | margin-right: 0%; 847 | margin-left: 0; 848 | } 849 | } 850 | caption { 851 | text-align: right; 852 | } 853 | th { 854 | text-align: right; 855 | } 856 | @media screen and (max-width: 767px) { 857 | .table-responsive > .table-bordered { 858 | border: 0; 859 | } 860 | .table-responsive > .table-bordered > thead > tr > th:first-child, 861 | .table-responsive > .table-bordered > tbody > tr > th:first-child, 862 | .table-responsive > .table-bordered > tfoot > tr > th:first-child, 863 | .table-responsive > .table-bordered > thead > tr > td:first-child, 864 | .table-responsive > .table-bordered > tbody > tr > td:first-child, 865 | .table-responsive > .table-bordered > tfoot > tr > td:first-child { 866 | border-right: 0; 867 | border-left: initial; 868 | } 869 | .table-responsive > .table-bordered > thead > tr > th:last-child, 870 | .table-responsive > .table-bordered > tbody > tr > th:last-child, 871 | .table-responsive > .table-bordered > tfoot > tr > th:last-child, 872 | .table-responsive > .table-bordered > thead > tr > td:last-child, 873 | .table-responsive > .table-bordered > tbody > tr > td:last-child, 874 | .table-responsive > .table-bordered > tfoot > tr > td:last-child { 875 | border-left: 0; 876 | border-right: initial; 877 | } 878 | } 879 | .radio label, 880 | .checkbox label { 881 | padding-right: 20px; 882 | padding-left: initial; 883 | } 884 | .radio input[type="radio"], 885 | .radio-inline input[type="radio"], 886 | .checkbox input[type="checkbox"], 887 | .checkbox-inline input[type="checkbox"] { 888 | margin-right: -20px; 889 | margin-left: auto; 890 | } 891 | .radio-inline, 892 | .checkbox-inline { 893 | padding-right: 20px; 894 | padding-left: 0; 895 | } 896 | .radio-inline + .radio-inline, 897 | .checkbox-inline + .checkbox-inline { 898 | margin-right: 10px; 899 | margin-left: 0; 900 | } 901 | .has-feedback .form-control { 902 | padding-left: 42.5px; 903 | padding-right: 12px; 904 | } 905 | .form-control-feedback { 906 | left: 0; 907 | right: auto; 908 | } 909 | @media (min-width: 768px) { 910 | .form-inline label { 911 | padding-right: 0; 912 | padding-left: initial; 913 | } 914 | .form-inline .radio input[type="radio"], 915 | .form-inline .checkbox input[type="checkbox"] { 916 | margin-right: 0; 917 | margin-left: auto; 918 | } 919 | } 920 | @media (min-width: 768px) { 921 | .form-horizontal .control-label { 922 | text-align: left; 923 | } 924 | } 925 | .form-horizontal .has-feedback .form-control-feedback { 926 | left: 15px; 927 | right: auto; 928 | } 929 | .caret { 930 | margin-right: 2px; 931 | margin-left: 0; 932 | } 933 | .dropdown-menu { 934 | right: 0; 935 | left: auto; 936 | float: left; 937 | text-align: right; 938 | } 939 | .dropdown-menu.pull-right { 940 | left: 0; 941 | right: auto; 942 | float: right; 943 | } 944 | .dropdown-menu-right { 945 | left: auto; 946 | right: 0; 947 | } 948 | .dropdown-menu-left { 949 | left: 0; 950 | right: auto; 951 | } 952 | @media (min-width: 768px) { 953 | .navbar-right .dropdown-menu { 954 | left: auto; 955 | right: 0; 956 | } 957 | .navbar-right .dropdown-menu-left { 958 | left: 0; 959 | right: auto; 960 | } 961 | } 962 | .btn-group > .btn, 963 | .btn-group-vertical > .btn { 964 | float: right; 965 | } 966 | .btn-group .btn + .btn, 967 | .btn-group .btn + .btn-group, 968 | .btn-group .btn-group + .btn, 969 | .btn-group .btn-group + .btn-group { 970 | margin-right: -1px; 971 | margin-left: 0px; 972 | } 973 | .btn-toolbar { 974 | margin-right: -5px; 975 | margin-left: 0px; 976 | } 977 | .btn-toolbar .btn-group, 978 | .btn-toolbar .input-group { 979 | float: right; 980 | } 981 | .btn-toolbar > .btn, 982 | .btn-toolbar > .btn-group, 983 | .btn-toolbar > .input-group { 984 | margin-right: 5px; 985 | margin-left: 0px; 986 | } 987 | .btn-group > .btn:first-child { 988 | margin-right: 0; 989 | } 990 | .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { 991 | border-top-right-radius: 4px; 992 | border-bottom-right-radius: 4px; 993 | border-bottom-left-radius: 0; 994 | border-top-left-radius: 0; 995 | } 996 | .btn-group > .btn:last-child:not(:first-child), 997 | .btn-group > .dropdown-toggle:not(:first-child) { 998 | border-top-left-radius: 4px; 999 | border-bottom-left-radius: 4px; 1000 | border-bottom-right-radius: 0; 1001 | border-top-right-radius: 0; 1002 | } 1003 | .btn-group > .btn-group { 1004 | float: right; 1005 | } 1006 | .btn-group.btn-group-justified > .btn, 1007 | .btn-group.btn-group-justified > .btn-group { 1008 | float: none; 1009 | } 1010 | .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { 1011 | border-radius: 0; 1012 | } 1013 | .btn-group > .btn-group:first-child > .btn:last-child, 1014 | .btn-group > .btn-group:first-child > .dropdown-toggle { 1015 | border-top-right-radius: 4px; 1016 | border-bottom-right-radius: 4px; 1017 | border-bottom-left-radius: 0; 1018 | border-top-left-radius: 0; 1019 | } 1020 | .btn-group > .btn-group:last-child > .btn:first-child { 1021 | border-top-left-radius: 4px; 1022 | border-bottom-left-radius: 4px; 1023 | border-bottom-right-radius: 0; 1024 | border-top-right-radius: 0; 1025 | } 1026 | .btn .caret { 1027 | margin-right: 0; 1028 | } 1029 | .btn-group-vertical > .btn + .btn, 1030 | .btn-group-vertical > .btn + .btn-group, 1031 | .btn-group-vertical > .btn-group + .btn, 1032 | .btn-group-vertical > .btn-group + .btn-group { 1033 | margin-top: -1px; 1034 | margin-right: 0; 1035 | } 1036 | .input-group .form-control { 1037 | float: right; 1038 | } 1039 | .input-group .form-control:first-child, 1040 | .input-group-addon:first-child, 1041 | .input-group-btn:first-child > .btn, 1042 | .input-group-btn:first-child > .btn-group > .btn, 1043 | .input-group-btn:first-child > .dropdown-toggle, 1044 | .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), 1045 | .input-group-btn:last-child > .btn-group:not(:last-child) > .btn { 1046 | border-bottom-right-radius: 4px; 1047 | border-top-right-radius: 4px; 1048 | border-bottom-left-radius: 0; 1049 | border-top-left-radius: 0; 1050 | } 1051 | .input-group-addon:first-child { 1052 | border-left: 0px; 1053 | border-right: 1px solid; 1054 | } 1055 | .input-group .form-control:last-child, 1056 | .input-group-addon:last-child, 1057 | .input-group-btn:last-child > .btn, 1058 | .input-group-btn:last-child > .btn-group > .btn, 1059 | .input-group-btn:last-child > .dropdown-toggle, 1060 | .input-group-btn:first-child > .btn:not(:first-child), 1061 | .input-group-btn:first-child > .btn-group:not(:first-child) > .btn { 1062 | border-bottom-left-radius: 4px; 1063 | border-top-left-radius: 4px; 1064 | border-bottom-right-radius: 0; 1065 | border-top-right-radius: 0; 1066 | } 1067 | .input-group-addon:last-child { 1068 | border-left-width: 1px; 1069 | border-left-style: solid; 1070 | border-right: 0px; 1071 | } 1072 | .input-group-btn > .btn + .btn { 1073 | margin-right: -1px; 1074 | margin-left: auto; 1075 | } 1076 | .input-group-btn:first-child > .btn, 1077 | .input-group-btn:first-child > .btn-group { 1078 | margin-left: -1px; 1079 | margin-right: auto; 1080 | } 1081 | .input-group-btn:last-child > .btn, 1082 | .input-group-btn:last-child > .btn-group { 1083 | margin-right: -1px; 1084 | margin-left: auto; 1085 | } 1086 | .nav { 1087 | padding-right: 0; 1088 | padding-left: initial; 1089 | } 1090 | .nav-tabs > li { 1091 | float: right; 1092 | } 1093 | .nav-tabs > li > a { 1094 | margin-left: auto; 1095 | margin-right: -2px; 1096 | border-radius: 4px 4px 0 0; 1097 | } 1098 | .nav-pills > li { 1099 | float: right; 1100 | } 1101 | .nav-pills > li > a { 1102 | border-radius: 4px; 1103 | } 1104 | .nav-pills > li + li { 1105 | margin-right: 2px; 1106 | margin-left: auto; 1107 | } 1108 | .nav-stacked > li { 1109 | float: none; 1110 | } 1111 | .nav-stacked > li + li { 1112 | margin-right: 0; 1113 | margin-left: auto; 1114 | } 1115 | .nav-justified > .dropdown .dropdown-menu { 1116 | right: auto; 1117 | } 1118 | .nav-tabs-justified > li > a { 1119 | margin-left: 0; 1120 | margin-right: auto; 1121 | } 1122 | @media (min-width: 768px) { 1123 | .nav-tabs-justified > li > a { 1124 | border-radius: 4px 4px 0 0; 1125 | } 1126 | } 1127 | @media (min-width: 768px) { 1128 | .navbar-header { 1129 | float: right; 1130 | } 1131 | } 1132 | .navbar-collapse { 1133 | padding-right: 15px; 1134 | padding-left: 15px; 1135 | } 1136 | .navbar-brand { 1137 | float: right; 1138 | } 1139 | @media (min-width: 768px) { 1140 | .navbar > .container .navbar-brand, 1141 | .navbar > .container-fluid .navbar-brand { 1142 | margin-right: -15px; 1143 | margin-left: auto; 1144 | } 1145 | } 1146 | .navbar-toggle { 1147 | float: left; 1148 | margin-left: 15px; 1149 | margin-right: auto; 1150 | } 1151 | @media (max-width: 767px) { 1152 | .navbar-nav .open .dropdown-menu > li > a, 1153 | .navbar-nav .open .dropdown-menu .dropdown-header { 1154 | padding: 5px 25px 5px 15px; 1155 | } 1156 | } 1157 | @media (min-width: 768px) { 1158 | .navbar-nav { 1159 | float: right; 1160 | } 1161 | .navbar-nav > li { 1162 | float: right; 1163 | } 1164 | } 1165 | @media (min-width: 768px) { 1166 | .navbar-left.flip { 1167 | float: right !important; 1168 | } 1169 | .navbar-right:last-child { 1170 | margin-left: -15px; 1171 | margin-right: auto; 1172 | } 1173 | .navbar-right.flip { 1174 | float: left !important; 1175 | margin-left: -15px; 1176 | margin-right: auto; 1177 | } 1178 | .navbar-right .dropdown-menu { 1179 | left: 0; 1180 | right: auto; 1181 | } 1182 | } 1183 | @media (min-width: 768px) { 1184 | .navbar-text { 1185 | float: right; 1186 | } 1187 | .navbar-text.navbar-right:last-child { 1188 | margin-left: 0; 1189 | margin-right: auto; 1190 | } 1191 | } 1192 | .pagination { 1193 | padding-right: 0; 1194 | } 1195 | .pagination > li > a, 1196 | .pagination > li > span { 1197 | float: right; 1198 | margin-right: -1px; 1199 | margin-left: 0px; 1200 | } 1201 | .pagination > li:first-child > a, 1202 | .pagination > li:first-child > span { 1203 | margin-left: 0; 1204 | border-bottom-right-radius: 4px; 1205 | border-top-right-radius: 4px; 1206 | border-bottom-left-radius: 0; 1207 | border-top-left-radius: 0; 1208 | } 1209 | .pagination > li:last-child > a, 1210 | .pagination > li:last-child > span { 1211 | margin-right: -1px; 1212 | border-bottom-left-radius: 4px; 1213 | border-top-left-radius: 4px; 1214 | border-bottom-right-radius: 0; 1215 | border-top-right-radius: 0; 1216 | } 1217 | .pager { 1218 | padding-right: 0; 1219 | padding-left: initial; 1220 | } 1221 | .pager .next > a, 1222 | .pager .next > span { 1223 | float: left; 1224 | } 1225 | .pager .previous > a, 1226 | .pager .previous > span { 1227 | float: right; 1228 | } 1229 | .nav-pills > li > a > .badge { 1230 | margin-left: 0px; 1231 | margin-right: 3px; 1232 | } 1233 | .list-group-item > .badge { 1234 | float: left; 1235 | } 1236 | .list-group-item > .badge + .badge { 1237 | margin-left: 5px; 1238 | margin-right: auto; 1239 | } 1240 | .alert-dismissable, 1241 | .alert-dismissible { 1242 | padding-left: 35px; 1243 | padding-right: 15px; 1244 | } 1245 | .alert-dismissable .close, 1246 | .alert-dismissible .close { 1247 | right: auto; 1248 | left: -21px; 1249 | } 1250 | .progress-bar { 1251 | float: right; 1252 | } 1253 | .media > .pull-left { 1254 | margin-right: 10px; 1255 | } 1256 | .media > .pull-left.flip { 1257 | margin-right: 0; 1258 | margin-left: 10px; 1259 | } 1260 | .media > .pull-right { 1261 | margin-left: 10px; 1262 | } 1263 | .media > .pull-right.flip { 1264 | margin-left: 0; 1265 | margin-right: 10px; 1266 | } 1267 | .media-right, 1268 | .media > .pull-right { 1269 | padding-right: 10px; 1270 | padding-left: initial; 1271 | } 1272 | .media-left, 1273 | .media > .pull-left { 1274 | padding-left: 10px; 1275 | padding-right: initial; 1276 | } 1277 | .media-list { 1278 | padding-right: 0; 1279 | padding-left: initial; 1280 | list-style: none; 1281 | } 1282 | .list-group { 1283 | padding-right: 0; 1284 | padding-left: initial; 1285 | } 1286 | .panel > .table:first-child > thead:first-child > tr:first-child td:first-child, 1287 | .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, 1288 | .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, 1289 | .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, 1290 | .panel > .table:first-child > thead:first-child > tr:first-child th:first-child, 1291 | .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, 1292 | .panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, 1293 | .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { 1294 | border-top-right-radius: 3px; 1295 | border-top-left-radius: 0; 1296 | } 1297 | .panel > .table:first-child > thead:first-child > tr:first-child td:last-child, 1298 | .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, 1299 | .panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, 1300 | .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, 1301 | .panel > .table:first-child > thead:first-child > tr:first-child th:last-child, 1302 | .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, 1303 | .panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, 1304 | .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { 1305 | border-top-left-radius: 3px; 1306 | border-top-right-radius: 0; 1307 | } 1308 | .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, 1309 | .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, 1310 | .panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, 1311 | .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, 1312 | .panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, 1313 | .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, 1314 | .panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, 1315 | .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { 1316 | border-bottom-left-radius: 3px; 1317 | border-top-right-radius: 0; 1318 | } 1319 | .panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, 1320 | .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, 1321 | .panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, 1322 | .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, 1323 | .panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, 1324 | .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, 1325 | .panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, 1326 | .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { 1327 | border-bottom-right-radius: 3px; 1328 | border-top-left-radius: 0; 1329 | } 1330 | .panel > .table-bordered > thead > tr > th:first-child, 1331 | .panel > .table-responsive > .table-bordered > thead > tr > th:first-child, 1332 | .panel > .table-bordered > tbody > tr > th:first-child, 1333 | .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, 1334 | .panel > .table-bordered > tfoot > tr > th:first-child, 1335 | .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, 1336 | .panel > .table-bordered > thead > tr > td:first-child, 1337 | .panel > .table-responsive > .table-bordered > thead > tr > td:first-child, 1338 | .panel > .table-bordered > tbody > tr > td:first-child, 1339 | .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, 1340 | .panel > .table-bordered > tfoot > tr > td:first-child, 1341 | .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { 1342 | border-right: 0; 1343 | border-left: none; 1344 | } 1345 | .panel > .table-bordered > thead > tr > th:last-child, 1346 | .panel > .table-responsive > .table-bordered > thead > tr > th:last-child, 1347 | .panel > .table-bordered > tbody > tr > th:last-child, 1348 | .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, 1349 | .panel > .table-bordered > tfoot > tr > th:last-child, 1350 | .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, 1351 | .panel > .table-bordered > thead > tr > td:last-child, 1352 | .panel > .table-responsive > .table-bordered > thead > tr > td:last-child, 1353 | .panel > .table-bordered > tbody > tr > td:last-child, 1354 | .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, 1355 | .panel > .table-bordered > tfoot > tr > td:last-child, 1356 | .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { 1357 | border-right: none; 1358 | border-left: 0; 1359 | } 1360 | .embed-responsive .embed-responsive-item, 1361 | .embed-responsive iframe, 1362 | .embed-responsive embed, 1363 | .embed-responsive object { 1364 | right: 0; 1365 | left: auto; 1366 | } 1367 | .close { 1368 | float: left; 1369 | } 1370 | .modal-footer { 1371 | text-align: left; 1372 | } 1373 | .modal-footer.flip { 1374 | text-align: right; 1375 | } 1376 | .modal-footer .btn + .btn { 1377 | margin-left: auto; 1378 | margin-right: 5px; 1379 | } 1380 | .modal-footer .btn-group .btn + .btn { 1381 | margin-right: -1px; 1382 | margin-left: auto; 1383 | } 1384 | .modal-footer .btn-block + .btn-block { 1385 | margin-right: 0; 1386 | margin-left: auto; 1387 | } 1388 | .popover { 1389 | left: auto; 1390 | text-align: right; 1391 | } 1392 | .popover.top > .arrow { 1393 | right: 50%; 1394 | left: auto; 1395 | margin-right: -11px; 1396 | margin-left: auto; 1397 | } 1398 | .popover.top > .arrow:after { 1399 | margin-right: -10px; 1400 | margin-left: auto; 1401 | } 1402 | .popover.bottom > .arrow { 1403 | right: 50%; 1404 | left: auto; 1405 | margin-right: -11px; 1406 | margin-left: auto; 1407 | } 1408 | .popover.bottom > .arrow:after { 1409 | margin-right: -10px; 1410 | margin-left: auto; 1411 | } 1412 | .carousel-control { 1413 | right: 0; 1414 | bottom: 0; 1415 | } 1416 | .carousel-control.left { 1417 | right: auto; 1418 | left: 0; 1419 | background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0%), color-stop(rgba(0, 0, 0, 0.0001) 100%)); 1420 | background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); 1421 | background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); 1422 | background-repeat: repeat-x; 1423 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); 1424 | } 1425 | .carousel-control.right { 1426 | left: auto; 1427 | right: 0; 1428 | background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0%), color-stop(rgba(0, 0, 0, 0.5) 100%)); 1429 | background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); 1430 | background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); 1431 | background-repeat: repeat-x; 1432 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); 1433 | } 1434 | .carousel-control .icon-prev, 1435 | .carousel-control .glyphicon-chevron-left { 1436 | left: 50%; 1437 | right: auto; 1438 | margin-right: -10px; 1439 | } 1440 | .carousel-control .icon-next, 1441 | .carousel-control .glyphicon-chevron-right { 1442 | right: 50%; 1443 | left: auto; 1444 | margin-left: -10px; 1445 | } 1446 | .carousel-indicators { 1447 | right: 50%; 1448 | left: 0; 1449 | margin-right: -30%; 1450 | margin-left: 0; 1451 | padding-left: 0; 1452 | } 1453 | @media screen and (min-width: 768px) { 1454 | .carousel-control .glyphicon-chevron-left, 1455 | .carousel-control .icon-prev { 1456 | margin-left: 0; 1457 | margin-right: -15px; 1458 | } 1459 | .carousel-control .glyphicon-chevron-right, 1460 | .carousel-control .icon-next { 1461 | margin-left: 0; 1462 | margin-right: -15px; 1463 | } 1464 | .carousel-caption { 1465 | left: 20%; 1466 | right: 20%; 1467 | padding-bottom: 30px; 1468 | } 1469 | } 1470 | .pull-right.flip { 1471 | float: left !important; 1472 | } 1473 | .pull-left.flip { 1474 | float: right !important; 1475 | } 1476 | /*# sourceMappingURL=bootstrap-rtl.css.map */ --------------------------------------------------------------------------------