{% trans "Nothing to preview" %}
19 |├── martor ├── tests │ ├── __init__.py │ ├── urls.py │ ├── views.py │ ├── models.py │ └── templates │ │ └── test_form_view.html ├── extensions │ ├── __init__.py │ ├── escape_html.py │ ├── mdx_add_id.py │ ├── del_ins.py │ ├── mention.py │ ├── urlize.py │ └── mdx_video.py ├── templatetags │ ├── __init__.py │ └── martortags.py ├── static │ ├── plugins │ │ ├── css │ │ │ ├── main-1.png │ │ │ ├── main-13.png │ │ │ ├── main-14.png │ │ │ ├── main-15.png │ │ │ ├── main-16.png │ │ │ ├── main-17.png │ │ │ ├── main-18.png │ │ │ ├── main-19.png │ │ │ ├── main-2.png │ │ │ ├── main-20.png │ │ │ ├── main-21.png │ │ │ ├── main-22.png │ │ │ ├── main-23.png │ │ │ ├── main-24.png │ │ │ ├── main-26.png │ │ │ ├── main-3.png │ │ │ ├── main-4.png │ │ │ ├── main-25.svg │ │ │ ├── main-5.svg │ │ │ ├── main-7.svg │ │ │ ├── main-8.svg │ │ │ ├── main-9.svg │ │ │ ├── highlight.min.css │ │ │ ├── main-6.svg │ │ │ ├── main-12.svg │ │ │ ├── main-10.svg │ │ │ └── main-11.svg │ │ ├── fonts │ │ │ ├── icons.eot │ │ │ ├── icons.ttf │ │ │ ├── icons.woff │ │ │ ├── icons.woff2 │ │ │ ├── brand-icons.eot │ │ │ ├── brand-icons.ttf │ │ │ ├── brand-icons.woff │ │ │ ├── brand-icons.woff2 │ │ │ ├── outline-icons.eot │ │ │ ├── outline-icons.ttf │ │ │ ├── outline-icons.woff │ │ │ └── outline-icons.woff2 │ │ ├── images │ │ │ ├── flags.png │ │ │ ├── heart.png │ │ │ └── commonmark.png │ │ └── js │ │ │ ├── snippets │ │ │ └── markdown.js │ │ │ ├── theme-github.js │ │ │ ├── spellcheck.js │ │ │ └── emojis.min.js │ ├── dicts │ │ ├── README.md │ │ └── en_US.aff │ └── martor │ │ └── css │ │ ├── martor-admin.min.css │ │ ├── martor-admin.css │ │ └── martor.semantic.min.css ├── locale │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── id │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── tr │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── __init__.py ├── admin.py ├── models.py ├── urls.py ├── fields.py ├── templates │ └── martor │ │ ├── semantic │ │ ├── emoji.html │ │ ├── editor.html │ │ ├── toolbar.html │ │ └── guide.html │ │ └── bootstrap │ │ ├── emoji.html │ │ ├── editor.html │ │ └── guide.html ├── api.py ├── utils.py ├── views.py ├── widgets.py └── settings.py ├── martor_demo ├── app │ ├── __init__.py │ ├── migrations │ │ ├── __init__.py │ │ └── .gitignore │ ├── apps.py │ ├── forms.py │ ├── urls.py │ ├── models.py │ ├── admin.py │ ├── views.py │ └── templates │ │ └── bootstrap │ │ └── test_markdownify.html ├── .gitignore ├── martor_demo │ ├── __init__.py │ ├── asgi.py │ ├── wsgi.py │ ├── urls.py │ └── settings.py └── manage.py ├── requirements.txt ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.md │ └── bug_report.md ├── dependabot.yml └── workflows │ ├── release.yml │ └── run-tests.yml ├── .etc └── images │ ├── semantic │ ├── martor-guide.png │ ├── martor-editor.png │ └── martor-preview.png │ └── bootstrap │ ├── martor-editor.png │ ├── martor-guide.png │ └── martor-preview.png ├── docs ├── requirements.txt ├── Makefile ├── changelog.rst ├── index.rst ├── installation.rst └── conf.py ├── docker-compose.yaml ├── pytest.ini ├── .flake8 ├── .gitignore ├── .readthedocs.yaml ├── .pre-commit-config.yaml ├── Dockerfile ├── runtests.py ├── tests └── collect-static │ ├── README.md │ └── test-collectstatic.sh ├── push.sh └── pyproject.toml /martor/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /martor_demo/app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /martor/extensions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /martor/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /martor_demo/.gitignore: -------------------------------------------------------------------------------- 1 | db.sqlite3 2 | -------------------------------------------------------------------------------- /martor_demo/app/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /martor_demo/martor_demo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /martor_demo/app/migrations/.gitignore: -------------------------------------------------------------------------------- 1 | [^.]* 2 | !__init__.py 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | urllib3 2 | zipp 3 | Django 4 | Markdown 5 | requests 6 | bleach 7 | tzdata 8 | -------------------------------------------------------------------------------- /martor_demo/app/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AppConfig(AppConfig): 5 | name = "app" 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [agusmakmun] 2 | ko_fi: 3 | liberapay: 4 | issuehunt: 5 | custom: ['https://www.paypal.me/summonagus'] 6 | -------------------------------------------------------------------------------- /.etc/images/semantic/martor-guide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/.etc/images/semantic/martor-guide.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-1.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-13.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-14.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-15.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-16.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-17.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-18.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-19.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-2.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-20.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-21.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-22.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-23.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-24.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-26.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-3.png -------------------------------------------------------------------------------- /martor/static/plugins/css/main-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/css/main-4.png -------------------------------------------------------------------------------- /martor/static/plugins/fonts/icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/icons.eot -------------------------------------------------------------------------------- /martor/static/plugins/fonts/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/icons.ttf -------------------------------------------------------------------------------- /.etc/images/bootstrap/martor-editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/.etc/images/bootstrap/martor-editor.png -------------------------------------------------------------------------------- /.etc/images/bootstrap/martor-guide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/.etc/images/bootstrap/martor-guide.png -------------------------------------------------------------------------------- /.etc/images/semantic/martor-editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/.etc/images/semantic/martor-editor.png -------------------------------------------------------------------------------- /.etc/images/semantic/martor-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/.etc/images/semantic/martor-preview.png -------------------------------------------------------------------------------- /martor/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /martor/locale/id/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/locale/id/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /martor/locale/tr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/locale/tr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /martor/static/plugins/fonts/icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/icons.woff -------------------------------------------------------------------------------- /martor/static/plugins/fonts/icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/icons.woff2 -------------------------------------------------------------------------------- /martor/static/plugins/images/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/images/flags.png -------------------------------------------------------------------------------- /martor/static/plugins/images/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/images/heart.png -------------------------------------------------------------------------------- /.etc/images/bootstrap/martor-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/.etc/images/bootstrap/martor-preview.png -------------------------------------------------------------------------------- /martor/static/plugins/fonts/brand-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/brand-icons.eot -------------------------------------------------------------------------------- /martor/static/plugins/fonts/brand-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/brand-icons.ttf -------------------------------------------------------------------------------- /martor/static/plugins/fonts/brand-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/brand-icons.woff -------------------------------------------------------------------------------- /martor/static/plugins/images/commonmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/images/commonmark.png -------------------------------------------------------------------------------- /martor/static/plugins/fonts/brand-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/brand-icons.woff2 -------------------------------------------------------------------------------- /martor/static/plugins/fonts/outline-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/outline-icons.eot -------------------------------------------------------------------------------- /martor/static/plugins/fonts/outline-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/outline-icons.ttf -------------------------------------------------------------------------------- /martor/static/plugins/fonts/outline-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/outline-icons.woff -------------------------------------------------------------------------------- /martor/static/plugins/fonts/outline-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/HEAD/martor/static/plugins/fonts/outline-icons.woff2 -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx>=5.0.0 2 | sphinx-rtd-theme>=1.0.0 3 | Django>=3.2 4 | Markdown>=3.0 5 | requests>=2.12.4 6 | bleach 7 | urllib3 8 | zipp 9 | tzdata 10 | -------------------------------------------------------------------------------- /martor/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "1.7.16" 2 | __release_date__ = "01-Nov-2025" 3 | __author__ = "Agus Makmun (Summon Agus)" 4 | __author_email__ = "summon.agus@gmail.com" 5 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | services: 3 | web: 4 | build: . 5 | ports: 6 | - "8000:8000" 7 | container_name: martor_demo 8 | restart: unless-stopped 9 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [tool:pytest] 2 | DJANGO_SETTINGS_MODULE = martor.tests.settings 3 | python_files = tests.py test_*.py *_tests.py 4 | addopts = -v --tb=short 5 | testpaths = martor/tests 6 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 120 3 | ignore = E402,E501,W503,W504,E731,E741 4 | exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,.vscode,build,dist,*.egg-info 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Question 4 | url: https://stackoverflow.com/questions/tagged/martor 5 | about: Please ask and answer questions here. 6 | -------------------------------------------------------------------------------- /martor/tests/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import include, path 2 | 3 | from .views import TestFormView 4 | 5 | urlpatterns = [ 6 | path("test-form-view/", TestFormView.as_view()), 7 | path("martor/", include("martor.urls")), 8 | ] 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a feature or enhancement 4 | --- 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /martor/tests/views.py: -------------------------------------------------------------------------------- 1 | from django.views.generic.edit import CreateView 2 | 3 | from .models import Post 4 | 5 | 6 | class TestFormView(CreateView): 7 | template_name = "test_form_view.html" 8 | model = Post 9 | fields = ["description", "wiki"] 10 | -------------------------------------------------------------------------------- /martor/tests/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from martor.models import MartorField 4 | 5 | 6 | class Post(models.Model): 7 | description = MartorField() 8 | wiki = MartorField() 9 | 10 | class Meta: 11 | app_label = "Post" 12 | -------------------------------------------------------------------------------- /martor/static/plugins/css/main-25.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /martor/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import MartorField 4 | from .widgets import AdminMartorWidget 5 | 6 | 7 | class MartorModelAdmin(admin.ModelAdmin): 8 | formfield_overrides = { 9 | MartorField: {"widget": AdminMartorWidget}, 10 | } 11 | -------------------------------------------------------------------------------- /martor/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from .fields import MartorFormField 4 | 5 | 6 | class MartorField(models.TextField): 7 | def formfield(self, **kwargs): 8 | defaults = {"form_class": MartorFormField} 9 | defaults.update(kwargs) 10 | return super().formfield(**defaults) 11 | -------------------------------------------------------------------------------- /martor/static/plugins/css/main-5.svg: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /martor/static/plugins/css/main-7.svg: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | ignore: 8 | # Ignore all patch releases as we can manually 9 | # upgrade if we run into a bug and need a fix. 10 | - dependency-name: "*" 11 | update-types: ["version-update:semver-patch"] 12 | -------------------------------------------------------------------------------- /martor/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from .views import markdown_imgur_uploader, markdown_search_user, markdownfy_view 4 | 5 | urlpatterns = [ 6 | path("markdownify/", markdownfy_view, name="martor_markdownfy"), 7 | path("uploader/", markdown_imgur_uploader, name="imgur_uploader"), 8 | path("search-user/", markdown_search_user, name="search_user_json"), 9 | ] 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report 4 | --- 5 | 6 | 7 | 8 | 9 | ## Details 10 | - OS (Operating System) version: 11 | - Browser and browser version: 12 | - Django version: 13 | - Martor version & theme: 14 | 15 | ### Steps to reproduce 16 | 17 | 1. 18 | 2. 19 | -------------------------------------------------------------------------------- /martor/static/plugins/css/main-8.svg: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /martor_demo/app/forms.py: -------------------------------------------------------------------------------- 1 | from app.models import Post 2 | from django import forms 3 | 4 | from martor.fields import MartorFormField 5 | 6 | 7 | class SimpleForm(forms.Form): 8 | title = forms.CharField(widget=forms.TextInput()) 9 | description = MartorFormField() 10 | wiki = MartorFormField() 11 | 12 | 13 | class PostForm(forms.ModelForm): 14 | class Meta: 15 | model = Post 16 | fields = "__all__" 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | build/ 3 | dist/ 4 | venv/ 5 | *.egg-info/ 6 | *.pypirc 7 | *.pyc 8 | *note 9 | *backup* 10 | 11 | # Hatch 12 | .hatch/ 13 | 14 | # Testing and coverage 15 | .pytest_cache/ 16 | .coverage 17 | htmlcov/ 18 | .tox/ 19 | 20 | # Type checking 21 | .mypy_cache/ 22 | 23 | # IDE 24 | .vscode/ 25 | .idea/ 26 | *.swp 27 | *.swo 28 | 29 | # OS 30 | .DS_Store 31 | Thumbs.db 32 | 33 | # Build documentation 34 | docs/_build/ 35 | -------------------------------------------------------------------------------- /martor/extensions/escape_html.py: -------------------------------------------------------------------------------- 1 | import markdown 2 | 3 | 4 | class EscapeHtml(markdown.Extension): 5 | def extendMarkdown(self, md: markdown.core.Markdown, *args): 6 | md.preprocessors.deregister("html_block") 7 | md.inlinePatterns.deregister("html") 8 | 9 | 10 | def makeExtension(*args, **kwargs): 11 | return EscapeHtml(*args, **kwargs) 12 | 13 | 14 | if __name__ == "__main__": 15 | import doctest 16 | 17 | doctest.testmod() 18 | -------------------------------------------------------------------------------- /martor_demo/app/urls.py: -------------------------------------------------------------------------------- 1 | from app.views import ( 2 | home_redirect_view, 3 | post_form_view, 4 | simple_form_view, 5 | test_markdownify, 6 | ) 7 | from django.urls import path 8 | 9 | urlpatterns = [ 10 | path("", home_redirect_view, name="home_redirect"), 11 | path("simple-form/", simple_form_view, name="simple_form"), 12 | path("post-form/", post_form_view, name="post_form"), 13 | path("test-markdownify/", test_markdownify, name="test_markdownify"), 14 | ] 15 | -------------------------------------------------------------------------------- /martor/static/plugins/css/main-9.svg: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /martor_demo/martor_demo/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for martor_demo project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "martor_demo.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /martor_demo/martor_demo/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for martor_demo 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/4.0/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", "martor_demo.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /martor/fields.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from .settings import MARTOR_ENABLE_LABEL 4 | from .widgets import MartorWidget 5 | 6 | 7 | class MartorFormField(forms.CharField): 8 | def __init__(self, *args, **kwargs): 9 | # to setup the editor without label 10 | if not MARTOR_ENABLE_LABEL: 11 | kwargs["label"] = "" 12 | 13 | super().__init__(*args, **kwargs) 14 | 15 | if not issubclass(self.widget.__class__, MartorWidget): 16 | self.widget = MartorWidget() 17 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version, and other tools you might need 8 | build: 9 | os: ubuntu-24.04 10 | tools: 11 | python: "3.13" 12 | 13 | # Build documentation in the "docs/" directory with Sphinx 14 | sphinx: 15 | configuration: docs/conf.py 16 | 17 | # Python requirements for building documentation 18 | python: 19 | install: 20 | - requirements: docs/requirements.txt 21 | -------------------------------------------------------------------------------- /martor/templatetags/martortags.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from django.utils.safestring import mark_safe 3 | 4 | from ..utils import markdownify 5 | 6 | register = template.Library() 7 | 8 | 9 | @register.filter 10 | def safe_markdown(markdown_text): 11 | """ 12 | Safe the markdown text as html output. 13 | 14 | Usage: 15 | {% load martortags %} 16 | {{ markdown_text|safe_markdown }} 17 | 18 | Example: 19 | {{ post.description|safe_markdown }} 20 | """ 21 | return mark_safe(markdownify(markdown_text)) 22 | -------------------------------------------------------------------------------- /martor/static/dicts/README.md: -------------------------------------------------------------------------------- 1 | The text below is copied from @cfinke's [Typo.js project](https://github.com/cfinke/Typo.js/tree/master/typo/dictionaries/en_US): 2 | 3 | 2006-02-07 release. 4 | 5 | This dictionary is based on a subset of the original English wordlist created by Kevin Atkinson for Pspell and Aspell and thus is covered by his original LGPL license. The affix file is a heavily modified version of the original english.aff file which was released as part of Geoff Kuenning's Ispell and as such is covered by his BSD license. 6 | 7 | Thanks to both authors for their wonderful work. 8 | -------------------------------------------------------------------------------- /martor/templates/martor/semantic/emoji.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
{% trans "Nothing to preview" %}
19 |This is added content and this is deleted content
13 |
hello summonagus, 18 | i mentioned you!
' 19 | >>> 20 | """ 21 | 22 | MENTION_RE = r"(?div{width:100%}fieldset .form-row .main-martor{display:grid!important}.submit-row a.deletelink{height:unset}.table.markdown-reference h2{font-size:1.5em;background:none;color:unset;padding:0;font-weight:300!important}.js-inline-admin-formset .form-row:not(.empty-form){display:revert}table{caption-side:top}@media (prefers-color-scheme:dark){body{color:#fff;background:#121212!important}h1,h3,h5{color:#fff!important}.modal-help-guide .modal-content{background:#121212!important}.modal-help-guide .modal-title{color:#333!important;font-size:unset!important;margin:0!important}.modal-help-guide .table.markdown-reference{background:#fff;color:#fff}.modal-help-guide .content{background:#121212!important}.tab-martor-menu .item,.martor-toolbar .ui.basic.buttons .button{color:#fff!important}} 10 | -------------------------------------------------------------------------------- /martor/static/plugins/js/snippets/markdown.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Ace v1.15.3 3 | * https://cdnjs.com/libraries/ace/ 4 | * https://github.com/ajaxorg/ace-builds/blob/v1.15.3/src-min-noconflict/snippets/markdown.js 5 | */ 6 | ace.define("ace/snippets/markdown.snippets",["require","exports","module"],function(e,t,n){n.exports='# Markdown\n\n# Includes octopress (http://octopress.org/) snippets\n\nsnippet [\n [${1:text}](http://${2:address} "${3:title}")\nsnippet [*\n [${1:link}](${2:`@*`} "${3:title}")${4}\n\nsnippet [:\n [${1:id}]: http://${2:url} "${3:title}"\nsnippet [:*\n [${1:id}]: ${2:`@*`} "${3:title}"\n\nsnippet \nsnippet ${4}\n\nsnippet ![:\n ![${1:id}]: ${2:url} "${3:title}"\nsnippet ![:*\n ![${1:id}]: ${2:`@*`} "${3:title}"\n\nsnippet ===\nregex /^/=+/=*//\n ${PREV_LINE/./=/g}\n \n ${0}\nsnippet ---\nregex /^/-+/-*//\n ${PREV_LINE/./-/g}\n \n ${0}\nsnippet blockquote\n {% blockquote %}\n ${1:quote}\n {% endblockquote %}\n\nsnippet blockquote-author\n {% blockquote ${1:author}, ${2:title} %}\n ${3:quote}\n {% endblockquote %}\n\nsnippet blockquote-link\n {% blockquote ${1:author} ${2:URL} ${3:link_text} %}\n ${4:quote}\n {% endblockquote %}\n\nsnippet bt-codeblock-short\n ```\n ${1:code_snippet}\n ```\n\nsnippet bt-codeblock-full\n ``` ${1:language} ${2:title} ${3:URL} ${4:link_text}\n ${5:code_snippet}\n ```\n\nsnippet codeblock-short\n {% codeblock %}\n ${1:code_snippet}\n {% endcodeblock %}\n\nsnippet codeblock-full\n {% codeblock ${1:title} lang:${2:language} ${3:URL} ${4:link_text} %}\n ${5:code_snippet}\n {% endcodeblock %}\n\nsnippet gist-full\n {% gist ${1:gist_id} ${2:filename} %}\n\nsnippet gist-short\n {% gist ${1:gist_id} %}\n\nsnippet img\n {% img ${1:class} ${2:URL} ${3:width} ${4:height} ${5:title_text} ${6:alt_text} %}\n\nsnippet youtube\n {% youtube ${1:video_id} %}\n\n# The quote should appear only once in the text. It is inherently part of it.\n# See http://octopress.org/docs/plugins/pullquote/ for more info.\n\nsnippet pullquote\n {% pullquote %}\n ${1:text} {" ${2:quote} "} ${3:text}\n {% endpullquote %}\n'}),ace.define("ace/snippets/markdown",["require","exports","module","ace/snippets/markdown.snippets"],function(e,t,n){"use strict";t.snippetText=e("./markdown.snippets"),t.scope="markdown"}); (function() { 7 | ace.require(["ace/snippets/markdown"], function(m) { 8 | if (typeof module == "object" && typeof exports == "object" && module) { 9 | module.exports = m; 10 | } 11 | }); 12 | })(); 13 | -------------------------------------------------------------------------------- /martor/utils.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import bleach 4 | from django.core.serializers.json import DjangoJSONEncoder 5 | from django.utils.functional import Promise 6 | 7 | try: 8 | from django.utils.encoding import force_str # noqa: Django>=4.x 9 | except ImportError: 10 | from django.utils.encoding import force_text as force_str # noqa: Django<=3.x 11 | 12 | import markdown 13 | 14 | from .settings import ( 15 | ALLOWED_HTML_ATTRIBUTES, 16 | ALLOWED_HTML_TAGS, 17 | ALLOWED_URL_SCHEMES, 18 | MARTOR_MARKDOWN_EXTENSION_CONFIGS, 19 | MARTOR_MARKDOWN_EXTENSIONS, 20 | ) 21 | 22 | 23 | def markdownify(markdown_text): 24 | """ 25 | Render the markdown content to HTML. 26 | 27 | Basic: 28 | >>> from martor.utils import markdownify 29 | >>> content = "" 30 | >>> markdownify(content) 31 | '
go to http://example.com
' 17 | 18 | >>> md.convert('example.com') 19 | u'' 20 | 21 | >>> md.convert('example.net') 22 | u'' 23 | 24 | >>> md.convert('www.example.us') 25 | u'' 26 | 27 | >>> md.convert('(www.example.us/path/?name=val)') 28 | u'(www.example.us/path/?name=val)
' 29 | 30 | >>> md.convert('go togo to http://example.com now!
' 32 | 33 | Negative examples: 34 | 35 | >>> md.convert('del.icio.us') 36 | u'del.icio.us
' 37 | 38 | """ 39 | 40 | from xml.etree import ElementTree 41 | 42 | import markdown 43 | 44 | # Global Vars 45 | URLIZE_RE = "(%s)" % "|".join( 46 | [ 47 | r"<(?:f|ht)tps?://[^>]*>", 48 | r"\b(?:f|ht)tps?://[^)<>\s]+[^.,)<>\s]", 49 | r"\bwww\.[^)<>\s]+[^.,)<>\s]", 50 | r"[^(<\s]+\.(?:com|net|org)\b", 51 | ] 52 | ) 53 | 54 | 55 | class UrlizePattern(markdown.inlinepatterns.Pattern): 56 | """Return a link Element given an autolink (`http://example/com`).""" 57 | 58 | def handleMatch(self, m): 59 | url = m.group(2) 60 | 61 | if url.startswith("<"): 62 | url = url[1:-1] 63 | 64 | text = url 65 | 66 | if url.split("://")[0] not in ("http", "https", "ftp"): 67 | if "@" in url and "/" not in url: 68 | url = "mailto:" + url 69 | else: 70 | url = "http://" + url 71 | 72 | el = ElementTree.Element("a") 73 | el.set("href", url) 74 | el.text = markdown.util.AtomicString(text) 75 | return el 76 | 77 | 78 | class UrlizeExtension(markdown.Extension): 79 | """Urlize Extension for Python-Markdown.""" 80 | 81 | def extendMarkdown(self, md: markdown.core.Markdown, *args): 82 | """Replace autolink with UrlizePattern""" 83 | md.inlinePatterns.register(UrlizePattern(URLIZE_RE, md), "autolink", 14) 84 | 85 | 86 | def makeExtension(*args, **kwargs): 87 | return UrlizeExtension(*args, **kwargs) 88 | 89 | 90 | if __name__ == "__main__": 91 | import doctest 92 | 93 | doctest.testmod() 94 | -------------------------------------------------------------------------------- /tests/collect-static/README.md: -------------------------------------------------------------------------------- 1 | # ACE Icons collectstatic Fix - Final Demo 2 | 3 | This directory contains the comprehensive demonstration of the ACE editor icons fix that resolves the `collectstatic` error. 4 | 5 | ## 🎭 Final Demonstration 6 | 7 | The `test-collectstatic.sh` script provides a complete demonstration showing: 8 | 9 | 1. ✅ **Current State Check** - Verifies all 26 icon files are present 10 | 2. ✅ **Initial Test** - Confirms collectstatic works with all files 11 | 3. 🔴 **Error Simulation** - Removes 5 critical icon files to recreate the original error 12 | 4. ❌ **Error Demonstration** - Shows the exact `MissingFileError` that occurs 13 | 5. ✅ **Fix Application** - Restores the missing files 14 | 6. 🎉 **Success Verification** - Confirms collectstatic works with all files present 15 | 16 | ## 🚀 Usage 17 | 18 | ```bash 19 | cd tests/collect-static 20 | ./test-collectstatic.sh 21 | ``` 22 | 23 | ## 📋 Files 24 | 25 | | File | Purpose | 26 | |------|---------| 27 | | `test-collectstatic.sh` | **Complete demonstration script** (error → fix → success) | 28 | | `README.md` | This documentation | 29 | 30 | ## 🎯 What This Demonstrates 31 | 32 | ### ❌ The Original Error 33 | ``` 34 | whitenoise.storage.MissingFileError: The file 'plugins/css/main-1.png' could not be found 35 | 36 | The CSS file 'plugins/css/ace.min.css' references a file which could not be found: 37 | plugins/css/main-1.png 38 | ``` 39 | 40 | ### ✅ The Fix 41 | - Downloaded 26 missing icon files from [ACE builds repository](https://github.com/ajaxorg/ace-builds/tree/v1.37.5/css) 42 | - Files: `main-1.png` through `main-26.png` and `main-5.svg` through `main-25.svg` 43 | - Located in: `martor/static/plugins/css/` 44 | 45 | ### 🔧 Why It Works 46 | 1. **Problem**: `ace.min.css` references icon files that weren't included 47 | 2. **Detection**: WhiteNoise's `CompressedManifestStaticFilesStorage` validates all CSS references 48 | 3. **Solution**: Add the missing files from official ACE repository 49 | 4. **Result**: All references satisfied, `collectstatic` succeeds 50 | 51 | ## 🛠️ Requirements 52 | 53 | - Docker (for build testing) 54 | - Python 3.x with Django 55 | - `whitenoise` package: `pip install whitenoise` 56 | 57 | ## 📊 Expected Output 58 | 59 | The demo will show: 60 | - ✅ **Current state**: 26 icon files found → Docker build succeeds 61 | - ❌ **Error state**: 5 files removed → collectstatic fails with `MissingFileError` 62 | - ✅ **Fixed state**: Files restored → collectstatic succeeds again 63 | 64 | This definitively proves that the missing ACE icon files were the root cause and that our fix permanently resolves the issue. 65 | 66 | ## 🎉 Result 67 | 68 | After running the demo, you'll have concrete proof that: 69 | 1. The original error was caused by missing ACE editor icon files 70 | 2. The fix (adding the 26 icon files) completely resolves the issue 71 | 3. The solution works in both local and Docker environments 72 | 4. The fix is permanent and robust 73 | -------------------------------------------------------------------------------- /martor/templates/martor/bootstrap/editor.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |{% blocktrans with repo_url='https://github.com/agusmakmun/django-markdown-editor' %}Copyright © Martor{% endblocktrans %}
9 |{% blocktrans with doc_url='http://commonmark.org/help/' %}This editor is powered by Markdown. For full 12 | documentation, click here.{% endblocktrans %}
13 || {% trans "Code" %} | 18 |{% trans "Or" %} | 19 |Linux/Windows | 20 |Mac OS | 21 |{% trans "... to Get" %} | 22 |
|---|---|---|---|---|
| :emoji_name: | 28 |— | 29 |— | 30 |— | 31 |![]() |
32 |
| @[username] | 38 |— | 39 |Ctrl+M | 40 |Command+M | 41 |@username | 42 |
| 48 | | ||||
| *Italic* | 53 |_Italic_ | 54 |Ctrl+I | 55 |Command+I | 56 |Italic | 57 |
| **Bold** | 60 |__Bold__ | 61 |Ctrl+B | 62 |Command+B | 63 |Bold | 64 |
| ++Underscores++ | 67 |— | 68 |Ctrl+Shift+U | 69 |Command+Shift+U | 70 |Underscores | 71 |
| ~~Strikethrough~~ | 74 |— | 75 |Ctrl+Shift+S | 76 |Command+Shift+S | 77 ||
| # Heading 1 | 81 |Heading 1 ========= |
82 | Ctrl+Alt+1 | 83 |Command+Option+1 | 84 |
85 | Heading 186 | |
87 |
| ## Heading 2 | 90 |Heading 2 ----------- |
91 | Ctrl+Alt+2 | 92 |Command+Option+2 | 93 |
94 | Heading 295 | |
96 |
| [Link](http://a.com) | 99 |[Link][1] ⁝ [1]: http://b.org |
100 | Ctrl+L | 101 |Command+L | 102 |Link | 103 |
|  | 106 |![Image][1] ⁝ [1]: http://url/b.jpg |
107 | Ctrl+Shift+I | 108 |Command+Option+I | 109 ||
| > Blockquote | 113 |— | 114 |Ctrl+Q | 115 |Command+Shift+K | 116 |
117 | Blockquote118 | |
119 |
| A paragraph. A paragraph after 1 blank line. |
122 | — | 123 |— | 124 |— | 125 |
126 | A paragraph. 127 |A paragraph after 1 blank line. 128 | |
129 |
|
132 | * List |
134 |
135 | - List |
137 | Ctrl+U | 138 |Command+U | 139 |
140 |
|
146 |
|
149 | 1. One |
151 |
152 | 1) One |
154 | Ctrl+Shift+O | 155 |Command+Option+O | 156 |
157 |
|
163 |
| Horizontal Rule ----------- |
166 | Horizontal Rule *********** |
167 | Ctrl+H | 168 |Command+H | 169 |Horizontal Rule
170 | 171 | |
172 |
| `Inline code` with backticks | 175 |— | 176 |Ctrl+Alt+C | 177 |Command+Option+C | 178 |Inline code with backticks |
179 |
| ``` def whatever(foo): return foo ``` |
182 | with tab / 4 spaces ....def whatever(foo): .... return foo |
183 | Ctrl+Alt+P | 184 |Command+Option+P | 185 |
186 | def whatever(foo):187 | |
188 |
See how your markdown content is beautifully rendered with Martor
146 |