mirror of
https://github.com/Hopiu/django-markdownx.git
synced 2026-05-10 14:24:43 +00:00
Merge branch 'master' of https://github.com/adi-/django-markdownx
* 'master' of https://github.com/adi-/django-markdownx: __init__ import altered. Minor clean up. # Conflicts: # setup.py
This commit is contained in:
commit
bffa7bb893
10 changed files with 111 additions and 116 deletions
|
|
@ -6,46 +6,18 @@
|
|||
# ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
|
||||
# Documentations
|
||||
# ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
|
||||
__credits__ = 'Adi, Pouria Hadjibagheri'
|
||||
__copyright__ = 'Copyright 2017'
|
||||
__license__ = 'BSD'
|
||||
__maintainer__ = 'Adi, Pouria Hadjibagheri'
|
||||
__url__ = 'https://github.com/neutronX/django-markdownx'
|
||||
__version__ = '2.0.1'
|
||||
__description__ = 'A comprehensive Markdown editor built for Django.'
|
||||
__long_description__ = '''
|
||||
__long_description__ = '''================
|
||||
Django MarkdownX
|
||||
''' + __url__ + '''
|
||||
|
||||
Key features
|
||||
------------
|
||||
|
||||
* raw editing
|
||||
* live preview
|
||||
* drag&drop image uploads (stored locally in `MEDIA` folder)
|
||||
* customizable image insertion tag
|
||||
* image filtering using content types and max file size
|
||||
* image manipulations (compression, size, cropping, upscaling)
|
||||
* pre-&post- text altering
|
||||
* easy template customization for layout purposes
|
||||
* multiple editors on one page
|
||||
* Django Admin support
|
||||
|
||||
Preview
|
||||
-------
|
||||
|
||||
.. image:: https://github.com/adi-/django-markdownx/raw/master/django-markdownx-preview.gif?raw=true
|
||||
:target: https://github.com/adi-/django-markdownx
|
||||
:alt: django-markdownx preview
|
||||
|
||||
*(using Bootstrap for layout and styling)*
|
||||
'''
|
||||
|
||||
'''Django MarkdownX
|
||||
================
|
||||
|
||||
|PyPi_Status| |Build_Status| |Format| |Supported_versions_of_Python| |Supported_versions_of_Django| |License|
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=adi-&repo=django-markdownx&type=star&count=true"
|
||||
frameborder="0" scrolling="0" width="120px" height="20px"></iframe>
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=adi-&repo=django-markdownx&type=watch&count=true&v=2"
|
||||
frameborder="0" scrolling="0" width="120px" height="20px"></iframe>
|
||||
|PyPi_Status| |Build_Status| |Format| |Supported_versions_of_Python| |Supported_versions_of_Django| |License| |GitHub Star| |GitHub Watch|
|
||||
|
||||
------------
|
||||
|
||||
|
|
@ -85,15 +57,9 @@ Key features
|
|||
.. |Supported_versions_of_Python| image:: https://img.shields.io/pypi/pyversions/django-markdownx.svg
|
||||
.. |Supported_versions_of_Django| image:: https://img.shields.io/badge/Django-1.8,%201.9,%201.10-green.svg
|
||||
.. |License| image:: https://img.shields.io/pypi/l/django-markdownx.svg
|
||||
|
||||
------------
|
||||
.. |GitHub Star| image:: https://img.shields.io/github/stars/neutronx/django-markdownx.svg?style=social&label=Star
|
||||
.. |GitHub Watch| image:: https://img.shields.io/github/watchers/neutronx/django-markdownx.svg?style=social&label=Watch
|
||||
'''
|
||||
__credits__ = 'Adi, Pouria Hadjibagheri'
|
||||
__copyright__ = 'Copyright 2017'
|
||||
__license__ = 'BSD'
|
||||
__maintainer__ = 'Adi, Pouria Hadjibagheri'
|
||||
__url__ = 'https://github.com/neutronX/django-markdownx'
|
||||
__version__ = '2.0.1'
|
||||
# ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
from django.contrib import admin
|
||||
from django.db import models
|
||||
|
||||
from .widgets import AdminMarkdownxWidget
|
||||
from .models import MarkdownxField
|
||||
|
||||
|
||||
class MarkdownxModelAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
|
||||
"""
|
||||
|
||||
formfield_overrides = {
|
||||
MarkdownxField: {'widget': AdminMarkdownxWidget}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from django import forms
|
||||
|
||||
from .widgets import MarkdownxWidget, AdminMarkdownxWidget
|
||||
from .widgets import MarkdownxWidget
|
||||
|
||||
|
||||
class MarkdownxFormField(forms.CharField):
|
||||
|
|
@ -19,10 +19,13 @@ class MarkdownxFormField(forms.CharField):
|
|||
super(MarkdownxFormField, self).__init__(*args, **kwargs)
|
||||
|
||||
if issubclass(self.widget.__class__, forms.widgets.MultiWidget):
|
||||
if not any([
|
||||
issubclass(x.__class__, MarkdownxWidget)
|
||||
for x in self.widget.widgets
|
||||
]):
|
||||
is_markdownx_widget = any(
|
||||
issubclass(item.__class__, MarkdownxWidget)
|
||||
for item in getattr(self.widget, 'widgets', list())
|
||||
)
|
||||
|
||||
if not is_markdownx_widget:
|
||||
self.widget = MarkdownxWidget()
|
||||
|
||||
elif not issubclass(self.widget.__class__, MarkdownxWidget):
|
||||
self.widget = MarkdownxWidget()
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from .views import (
|
|||
MarkdownifyView,
|
||||
)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^upload/$', ImageUploadView.as_view()),
|
||||
url(r'^markdownify/$', MarkdownifyView.as_view()),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@ from markdown import markdown
|
|||
|
||||
from PIL import Image
|
||||
|
||||
from .settings import MARKDOWNX_MARKDOWN_EXTENSIONS, MARKDOWNX_MARKDOWN_EXTENSION_CONFIGS
|
||||
from .settings import (
|
||||
MARKDOWNX_MARKDOWN_EXTENSIONS,
|
||||
MARKDOWNX_MARKDOWN_EXTENSION_CONFIGS
|
||||
)
|
||||
|
||||
|
||||
def markdownify(content):
|
||||
|
|
@ -21,6 +24,36 @@ def markdownify(content):
|
|||
return md
|
||||
|
||||
|
||||
def _crop(im, target_x, target_y):
|
||||
# Use integer values now.
|
||||
source_x, source_y = im.size
|
||||
# Difference between new image size and requested size.
|
||||
diff_x = int(source_x - min(source_x, target_x))
|
||||
diff_y = int(source_y - min(source_y, target_y))
|
||||
|
||||
if diff_x or diff_y:
|
||||
# Center cropping (default).
|
||||
halfdiff_x, halfdiff_y = diff_x // 2, diff_y // 2
|
||||
box = [
|
||||
halfdiff_x,
|
||||
halfdiff_y,
|
||||
min(source_x, int(target_x) + halfdiff_x),
|
||||
min(source_y, int(target_y) + halfdiff_y)
|
||||
]
|
||||
|
||||
# Finally, crop the image!
|
||||
im = im.crop(box)
|
||||
return im
|
||||
|
||||
|
||||
def _scale(im, x, y):
|
||||
im.resize(
|
||||
(int(x), int(y)),
|
||||
resample=Image.ANTIALIAS
|
||||
)
|
||||
return im
|
||||
|
||||
|
||||
def scale_and_crop(image, size, crop=False, upscale=False, quality=None):
|
||||
"""
|
||||
|
||||
|
|
@ -37,8 +70,6 @@ def scale_and_crop(image, size, crop=False, upscale=False, quality=None):
|
|||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
# ToDo: Possible IO/Runtime exceptions need to handled, and `finally` the file needs to be closed.
|
||||
|
||||
# Open image and store format/metadata.
|
||||
image.open()
|
||||
im = Image.open(image)
|
||||
|
|
@ -64,34 +95,16 @@ def scale_and_crop(image, size, crop=False, upscale=False, quality=None):
|
|||
target_y = source_y * scale
|
||||
|
||||
if scale < 1.0 or (scale > 1.0 and upscale):
|
||||
im = im.resize(
|
||||
(int(source_x * scale), int(source_y * scale)),
|
||||
resample=Image.ANTIALIAS
|
||||
)
|
||||
im = _scale(im=im, x=source_x * scale, y=source_y * scale)
|
||||
|
||||
if crop:
|
||||
# Use integer values now.
|
||||
source_x, source_y = im.size
|
||||
# Difference between new image size and requested size.
|
||||
diff_x = int(source_x - min(source_x, target_x))
|
||||
diff_y = int(source_y - min(source_y, target_y))
|
||||
|
||||
if diff_x or diff_y:
|
||||
# Center cropping (default).
|
||||
halfdiff_x, halfdiff_y = diff_x // 2, diff_y // 2
|
||||
box = [
|
||||
halfdiff_x,
|
||||
halfdiff_y,
|
||||
min(source_x, int(target_x) + halfdiff_x),
|
||||
min(source_y, int(target_y) + halfdiff_y)
|
||||
]
|
||||
|
||||
# Finally, crop the image!
|
||||
im = im.crop(box)
|
||||
im = _crop(im=im, target_x=target_x, target_y=target_y)
|
||||
|
||||
# Close image and replace format/metadata, as PIL blows this away.
|
||||
im.format, im.info = im_format, im_info
|
||||
|
||||
image.close()
|
||||
|
||||
return im
|
||||
|
||||
|
||||
|
|
@ -108,11 +121,7 @@ def has_javascript(data):
|
|||
# ------------------------------------------------
|
||||
# Handles JavaScript nodes and stringified nodes.
|
||||
# ------------------------------------------------
|
||||
pattern = (
|
||||
r'(<\s*\bscript\b.*>.*)|'
|
||||
r'(.*\bif\b\s*\(.?={2,3}.*\))|'
|
||||
r'(.*\bfor\b\s*\(.*\))'
|
||||
)
|
||||
pattern = r'(<\s*\bscript\b.*>.*)|(.*\bif\b\s*\(.?={2,3}.*\))|(.*\bfor\b\s*\(.*\))'
|
||||
|
||||
found = search(
|
||||
pattern=pattern,
|
||||
|
|
|
|||
55
setup.py
55
setup.py
|
|
@ -40,7 +40,6 @@ you have multiple versions installed on your machine:
|
|||
from setuptools import setup, find_packages
|
||||
from os import environ, link
|
||||
from os.path import join, dirname
|
||||
from re import compile as re_compile
|
||||
|
||||
|
||||
if 'vagrant' in str(environ):
|
||||
|
|
@ -48,38 +47,34 @@ if 'vagrant' in str(environ):
|
|||
|
||||
|
||||
def get_meta():
|
||||
values = {
|
||||
'description',
|
||||
'long_description',
|
||||
'credits',
|
||||
'copyright',
|
||||
'license',
|
||||
'maintainer',
|
||||
'url',
|
||||
'version'
|
||||
from sys import version_info
|
||||
|
||||
keys = {
|
||||
'__description__',
|
||||
'__long_description__',
|
||||
'__credits__',
|
||||
'__copyright__',
|
||||
'__license__',
|
||||
'__maintainer__',
|
||||
'__url__',
|
||||
'__version__'
|
||||
}
|
||||
|
||||
# Constructing the parsing pattern for metadata:
|
||||
template = str.join('|', values)
|
||||
pattern = re_compile(
|
||||
r"^_{{2}}"
|
||||
r"(?P<name>({}))"
|
||||
r"_{{2}}.+[\'\"]"
|
||||
r"(?P<value>(.+))"
|
||||
r"[\'\"][.\n]?$".format(template)
|
||||
)
|
||||
|
||||
meta = dict()
|
||||
|
||||
# Parsing metadata from `./markdownx/__init__.py`:
|
||||
path = join(dirname(__file__), 'markdownx', '__init__.py')
|
||||
with open(path, 'r') as data:
|
||||
for line in data:
|
||||
if not line.startswith('__'):
|
||||
continue
|
||||
found = pattern.search(line)
|
||||
if found is not None:
|
||||
meta[found.group('name')] = found.group('value')
|
||||
|
||||
if version_info.major == 3 and version_info.minor >= 5:
|
||||
import importlib.util
|
||||
spec = importlib.util.spec_from_file_location('.', path)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
elif version_info.major == 3:
|
||||
from importlib.machinery import SourceFileLoader
|
||||
mod = SourceFileLoader('.', path).load_module()
|
||||
else:
|
||||
import imp
|
||||
mod = imp.load_source('.', path)
|
||||
|
||||
meta = {key.replace('__', ''): getattr(mod, key) for key in keys}
|
||||
|
||||
return meta
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from django.db import models
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin import ModelAdmin, site
|
||||
|
||||
from markdownx.widgets import AdminMarkdownxWidget
|
||||
from markdownx.models import MarkdownxField
|
||||
|
|
@ -7,13 +7,14 @@ from markdownx.models import MarkdownxField
|
|||
from .models import MyModel
|
||||
|
||||
|
||||
class MyModelAdmin(admin.ModelAdmin):
|
||||
@site.register(MyModel)
|
||||
class MyModelAdmin(ModelAdmin):
|
||||
formfield_overrides = {
|
||||
MarkdownxField: {'widget': AdminMarkdownxWidget},
|
||||
models.TextField: {'widget': AdminMarkdownxWidget},
|
||||
}
|
||||
|
||||
admin.site.register(MyModel, MyModelAdmin)
|
||||
# site.register(MyModel, MyModelAdmin)
|
||||
|
||||
##
|
||||
## SHORTER OPTION:
|
||||
|
|
|
|||
|
|
@ -3,6 +3,16 @@ from django import forms
|
|||
from markdownx.fields import MarkdownxFormField
|
||||
from markdownx.widgets import MarkdownxWidget
|
||||
|
||||
|
||||
class MyForm(forms.Form):
|
||||
markdownx_form_field1 = MarkdownxFormField(widget=MarkdownxWidget(attrs={'class':'custom-class-markdownx_form_field1'}))
|
||||
markdownx_form_field2 = MarkdownxFormField(widget=MarkdownxWidget(attrs={'class':'custom-class-markdownx_form_field2'}))
|
||||
markdownx_form_field1 = MarkdownxFormField(
|
||||
widget=MarkdownxWidget(
|
||||
attrs={'class': 'custom-class-markdownx_form_field1'}
|
||||
)
|
||||
)
|
||||
|
||||
markdownx_form_field2 = MarkdownxFormField(
|
||||
widget=MarkdownxWidget(
|
||||
attrs={'class': 'custom-class-markdownx_form_field2'}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from testapp.views import (
|
|||
TestCreateView,
|
||||
)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', IndexTemplateView.as_view()),
|
||||
url(r'^form-view/$', TestFormView.as_view(), name='form_view'),
|
||||
|
|
|
|||
|
|
@ -8,13 +8,20 @@ from testapp.forms import MyForm
|
|||
class IndexTemplateView(TemplateView):
|
||||
template_name = 'index.html'
|
||||
|
||||
|
||||
class TestFormView(FormView):
|
||||
template_name = "test_form_view.html"
|
||||
form_class = MyForm
|
||||
success_url = '/'
|
||||
|
||||
|
||||
class TestCreateView(CreateView):
|
||||
template_name = "test_create_view.html"
|
||||
model = MyModel
|
||||
fields = ['markdownx_field1', 'markdownx_field2', 'textfield1', 'textfield2']
|
||||
success_url = '/'
|
||||
fields = [
|
||||
'markdownx_field1',
|
||||
'markdownx_field2',
|
||||
'textfield1',
|
||||
'textfield2'
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue