├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── intro.rst
├── resources
├── clipboardimage.gif
├── dropimage.gif
├── emoji.png
├── markdown.gif
└── without_admin.gif
├── setup.py
├── simditor
├── __init__.py
├── fields.py
├── image
│ ├── __init__.py
│ ├── dummy_backend.py
│ └── pillow_backend.py
├── image_processing.py
├── static
│ └── simditor
│ │ ├── fonts
│ │ ├── icomoon.eot
│ │ ├── icomoon.svg
│ │ ├── icomoon.ttf
│ │ ├── icomoon.woff
│ │ └── selection.json
│ │ ├── images
│ │ └── image.png
│ │ ├── scripts
│ │ ├── hotkeys.js
│ │ ├── hotkeys.min.js
│ │ ├── jquery.min.js
│ │ ├── markdown.all.js
│ │ ├── marked.min.js
│ │ ├── module.js
│ │ ├── module.min.js
│ │ ├── simditor-checklist.js
│ │ ├── simditor-checklist.min.js
│ │ ├── simditor-dropzone.js
│ │ ├── simditor-dropzone.min.js
│ │ ├── simditor-fullscreen.js
│ │ ├── simditor-fullscreen.min.js
│ │ ├── simditor-markdown.js
│ │ ├── simditor-markdown.min.js
│ │ ├── simditor.ext.min.js
│ │ ├── simditor.js
│ │ ├── simditor.main.min.js
│ │ ├── simditor.min.js
│ │ ├── to-markdown.js
│ │ ├── to-markdown.min.js
│ │ ├── uploader.js
│ │ └── uploader.min.js
│ │ ├── simditor-init.js
│ │ └── styles
│ │ ├── editor.scss
│ │ ├── fonticon.scss
│ │ ├── simditor-checklist.css
│ │ ├── simditor-checklist.min.css
│ │ ├── simditor-fullscreen.css
│ │ ├── simditor-fullscreen.min.css
│ │ ├── simditor-markdown.css
│ │ ├── simditor-markdown.min.css
│ │ ├── simditor.css
│ │ ├── simditor.main.min.css
│ │ ├── simditor.min.css
│ │ └── simditor.scss
├── templates
│ └── simditor
│ │ └── widget.html
├── urls.py
├── utils.py
├── views.py
└── widgets.py
├── simditor_demo
├── app
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── manage.py
├── simditor_demo
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── templates
│ └── index.html
└── tox.ini
/.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 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
103 | .DS_Store
104 | db.sqlite3
105 |
106 | simditor/static/
107 | static/
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 版本变更记录
2 |
3 | **0.0.15**
4 | - 添加图片最大上传限制
5 |
6 | **0.0.13**
7 |
8 | - 修改图片上传代码
9 | - 添加django admin之外的示例
10 |
11 |
12 | **0.0.12**
13 |
14 | - 修复Django2.1 之前版本兼容问题
15 |
16 | **0.0.11**
17 |
18 | - 修复Django2.1 renderer 报错
19 |
20 | **0.0.10**
21 |
22 | - 修复样式问题
23 |
24 | **0.0.8**
25 |
26 | - emoji 功能
27 |
28 |
29 | **0.0.5**
30 |
31 | - Markdown 功能
32 | - 图片上传
33 |
34 |
35 | **0.0.1**
36 |
37 | - 初始化目录
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 codingcat
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 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE
2 | include intro.rst
3 | recursive-include simditor/static *
4 | recursive-include simditor/templates *
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # django-simditor
2 | django simditor
3 |
4 | Installation
5 | ------------
6 |
7 | ```bash
8 | pip install django-simditor
9 | ```
10 |
11 | **Add `simditor` to your `INSTALLED_APPS` setting.**
12 |
13 | ```python
14 | from django.db import models
15 | from simditor.fields import RichTextField
16 |
17 |
18 | class Post(models.Model):
19 | content = RichTextField()
20 | ```
21 |
22 | **emoji**
23 |
24 | 
25 |
26 | **Markdown**
27 |
28 | 
29 |
30 | **Image upload config**
31 |
32 | *drop image*
33 |
34 | 
35 |
36 | *clipboard image*
37 |
38 | 
39 |
40 |
41 | `urls.py`
42 |
43 |
44 | ```python
45 | urlpatterns = [
46 | url(r'^admin/', admin.site.urls),
47 | url(r'^simditor/', include('simditor.urls')) # add this line
48 | ]
49 | ```
50 |
51 | `settings.py`
52 |
53 | ```python
54 | INSTALLED_APPS = [
55 | 'django.contrib.admin',
56 | 'django.contrib.auth',
57 | 'django.contrib.contenttypes',
58 | 'django.contrib.sessions',
59 | 'django.contrib.messages',
60 | 'django.contrib.staticfiles',
61 |
62 | 'simditor'
63 | ]
64 |
65 | SIMDITOR_UPLOAD_PATH = 'uploads/'
66 | SIMDITOR_IMAGE_BACKEND = 'pillow'
67 |
68 | SIMDITOR_TOOLBAR = [
69 | 'title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale',
70 | 'color', '|', 'ol', 'ul', 'blockquote', 'code', 'table', '|', 'link',
71 | 'image', 'hr', '|', 'indent', 'outdent', 'alignment', 'fullscreen',
72 | 'markdown', 'emoji'
73 | ]
74 |
75 | SIMDITOR_CONFIGS = {
76 | 'toolbar': SIMDITOR_TOOLBAR,
77 | 'upload': {
78 | 'url': '/simditor/upload/',
79 | 'fileKey': 'upload',
80 | 'image_size': 1024 * 1024 * 4 # max image size 4MB
81 | },
82 | 'emoji': {
83 | 'imagePath': '/static/simditor/images/emoji/'
84 | }
85 | }
86 | ```
87 |
88 | ## without django admin demo
89 |
90 | 
91 |
92 | ```python
93 | from django.views import generic
94 | from django.views.decorators.csrf import csrf_exempt
95 |
96 | from simditor.views import upload_handler
97 |
98 |
99 | class ImageUploadView(generic.View):
100 | """ImageUploadView."""
101 |
102 | http_method_names = ['post']
103 |
104 | def post(self, request, **kwargs):
105 | """Post."""
106 | return upload_handler(request)
107 |
108 |
109 | urlpatterns = [
110 | url(r'^$', IndexView.as_view(), name='simditor-form'),
111 | url(r'^simditor/upload', csrf_exempt(ImageUploadView.as_view())),
112 | ]
113 | ```
114 |
115 | ```python
116 | # IndexView
117 | from django import forms
118 |
119 | from django.views import generic
120 |
121 | from simditor.fields import RichTextFormField
122 | try:
123 | from django.urls import reverse
124 | except ImportError: # Django < 2.0
125 | from django.core.urlresolvers import reverse
126 |
127 |
128 | class SimditorForm(forms.Form):
129 | content = RichTextFormField()
130 |
131 |
132 | class IndexView(generic.FormView):
133 | form_class = SimditorForm
134 |
135 | template_name = 'index.html'
136 |
137 | def get_success_url(self):
138 | return reverse('simditor-form')
139 | ```
140 |
141 | `index.html`
142 |
143 | ```html
144 |
145 |
146 |
147 |
148 | Document
149 |
150 |
151 |
157 |
158 |
159 | ```
160 |
161 | > more detail you can check simditor_demo
162 |
--------------------------------------------------------------------------------
/intro.rst:
--------------------------------------------------------------------------------
1 | Django Simditor
2 | ===============
3 |
4 |
5 | Installation
6 | ------------
7 |
8 | pip install django-Simditor
9 |
10 |
11 | #. Add ``simditor`` to your ``INSTALLED_APPS`` setting.
12 |
--------------------------------------------------------------------------------
/resources/clipboardimage.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/resources/clipboardimage.gif
--------------------------------------------------------------------------------
/resources/dropimage.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/resources/dropimage.gif
--------------------------------------------------------------------------------
/resources/emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/resources/emoji.png
--------------------------------------------------------------------------------
/resources/markdown.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/resources/markdown.gif
--------------------------------------------------------------------------------
/resources/without_admin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/resources/without_admin.gif
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | """setup.py"""
2 | # -*- coding: utf-8 -*-
3 | #/usr/bin/env python
4 |
5 | from setuptools import setup, find_packages
6 |
7 | VERSION = '0.0.15'
8 | LONG_DESCRIPTION = open('intro.rst', 'r').read()
9 |
10 | INSTALL_REQUIRES = [
11 | 'Django',
12 | 'pillow'
13 | ]
14 |
15 | setup(
16 | name='django-simditor',
17 | version=VERSION,
18 | description='Django admin Simditor integration.',
19 | long_description=LONG_DESCRIPTION,
20 | author='Silence',
21 | author_email='istommao@gmail.com',
22 | url='https://github.com/istommao/django-simditor',
23 | zip_safe=False,
24 | install_requires=INSTALL_REQUIRES,
25 | packages=find_packages(exclude=[".DS_Store"]),
26 | keywords='Django admin Simditor integration!',
27 | include_package_data=True,
28 | classifiers=[
29 | "Programming Language :: Python",
30 | "Programming Language :: Python :: 2.7",
31 | "Programming Language :: Python :: 3.3",
32 | "Programming Language :: Python :: 3.4",
33 | "Programming Language :: Python :: 3.5",
34 | "License :: OSI Approved :: MIT License",
35 | "Operating System :: OS Independent",
36 | "Framework :: Django",
37 | "Intended Audience :: Developers",
38 | "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
39 | ]
40 | )
41 |
--------------------------------------------------------------------------------
/simditor/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/simditor/__init__.py
--------------------------------------------------------------------------------
/simditor/fields.py:
--------------------------------------------------------------------------------
1 | """simditor fields."""
2 | from django import forms
3 | from django.db import models
4 |
5 | from .widgets import SimditorWidget
6 |
7 |
8 | class RichTextFormField(forms.fields.CharField):
9 | """RichTextFormField."""
10 |
11 | def __init__(self, *args, **kwargs):
12 | kwargs.update(
13 | {
14 | 'widget': SimditorWidget()
15 | }
16 | )
17 | super(RichTextFormField, self).__init__(*args, **kwargs)
18 |
19 |
20 | class RichTextField(models.TextField):
21 | """RichTextField."""
22 |
23 | def __init__(self, *args, **kwargs):
24 | super(RichTextField, self).__init__(*args, **kwargs)
25 |
26 | def formfield(self, **kwargs):
27 | defaults = {
28 | 'form_class': self._get_form_class()
29 | }
30 | defaults.update(kwargs)
31 | return super(RichTextField, self).formfield(**defaults)
32 |
33 | @staticmethod
34 | def _get_form_class():
35 | return RichTextFormField
36 |
--------------------------------------------------------------------------------
/simditor/image/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/simditor/image/__init__.py
--------------------------------------------------------------------------------
/simditor/image/dummy_backend.py:
--------------------------------------------------------------------------------
1 | """simditor image pillow_backend."""
2 | from __future__ import absolute_import
3 |
4 | from simditor import utils
5 |
6 |
7 | def image_verify(file_object):
8 | """image_verify."""
9 | if not utils.is_valid_image_extension(file_object.name):
10 | raise utils.NotAnImageException
11 |
--------------------------------------------------------------------------------
/simditor/image/pillow_backend.py:
--------------------------------------------------------------------------------
1 | """simditor image pillow_backend."""
2 | from __future__ import absolute_import
3 |
4 | import os
5 | from io import BytesIO
6 |
7 | from django.core.files.storage import default_storage
8 | from django.core.files.uploadedfile import InMemoryUploadedFile
9 |
10 | from simditor import utils
11 |
12 | try:
13 | from PIL import Image, ImageOps
14 | except ImportError:
15 | import Image
16 | import ImageOps
17 |
18 |
19 | THUMBNAIL_SIZE = (75, 75)
20 |
21 |
22 | def image_verify(f):
23 | try:
24 | Image.open(f).verify()
25 | except IOError:
26 | raise utils.NotAnImageException
27 |
--------------------------------------------------------------------------------
/simditor/image_processing.py:
--------------------------------------------------------------------------------
1 | """simditor image_processing."""
2 | from __future__ import absolute_import
3 |
4 | from django.conf import settings
5 |
6 |
7 | def get_backend():
8 | """Get backend."""
9 | backend = getattr(settings, 'SIMDITOR_IMAGE_BACKEND', None)
10 |
11 | if backend == 'pillow':
12 | from simditor.image import pillow_backend as backend
13 | else:
14 | from simditor.image import dummy_backend as backend
15 | return backend
16 |
--------------------------------------------------------------------------------
/simditor/static/simditor/fonts/icomoon.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/simditor/static/simditor/fonts/icomoon.eot
--------------------------------------------------------------------------------
/simditor/static/simditor/fonts/icomoon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/simditor/static/simditor/fonts/icomoon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/simditor/static/simditor/fonts/icomoon.ttf
--------------------------------------------------------------------------------
/simditor/static/simditor/fonts/icomoon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/simditor/static/simditor/fonts/icomoon.woff
--------------------------------------------------------------------------------
/simditor/static/simditor/fonts/selection.json:
--------------------------------------------------------------------------------
1 | {
2 | "IcoMoonType": "selection",
3 | "icons": [
4 | {
5 | "icon": {
6 | "paths": [
7 | "M877.248 786.752l-146.752-146.752-90.496 90.496 146.752 146.752-146.752 146.752h384v-384zM384 0h-384v384l146.752-146.752 145.376 145.248 90.496-90.496-145.376-145.248zM384 730.496l-90.496-90.496-146.752 146.752-146.752-146.752v384h384l-146.752-146.752zM1024 0h-384l146.752 146.752-145.376 145.248 90.496 90.496 145.376-145.248 146.752 146.752z"
8 | ],
9 | "tags": [
10 | "fullscreen",
11 | "expand"
12 | ],
13 | "grid": 16,
14 | "attrs": []
15 | },
16 | "attrs": [],
17 | "properties": {
18 | "id": 99,
19 | "order": 2,
20 | "prevSize": 16,
21 | "code": 58880,
22 | "name": "fullscreen"
23 | },
24 | "setIdx": 1,
25 | "setId": 6,
26 | "iconIdx": 99
27 | }
28 | ],
29 | "height": 1024,
30 | "metadata": {
31 | "name": "icomoon"
32 | },
33 | "preferences": {
34 | "fontPref": {
35 | "prefix": "icon-",
36 | "metadata": {
37 | "fontFamily": "icomoon",
38 | "majorVersion": 1,
39 | "minorVersion": 0
40 | },
41 | "showGlyphs": true,
42 | "metrics": {
43 | "emSize": 512,
44 | "baseline": 6.25,
45 | "whitespace": 50
46 | },
47 | "resetPoint": 58880,
48 | "showQuickUse": true,
49 | "quickUsageToken": false,
50 | "showMetrics": false,
51 | "showMetadata": false,
52 | "autoHost": true,
53 | "embed": false,
54 | "ie7": false,
55 | "showSelector": false,
56 | "showVersion": true
57 | },
58 | "imagePref": {
59 | "color": 0,
60 | "height": 32,
61 | "columns": 16,
62 | "margin": 16,
63 | "png": false,
64 | "sprites": true,
65 | "prefix": "icon-"
66 | },
67 | "historySize": 100,
68 | "showCodes": true,
69 | "gridSize": 16,
70 | "showLiga": false,
71 | "showGrid": true,
72 | "showGlyphs": true,
73 | "showQuickUse": true,
74 | "search": "",
75 | "quickUsageToken": {
76 | "UntitledProject1": "ZWEwOTk2NTRmNjMyOGQ1MzAwZWFiYmJlODViMWMzZDcjMiMxNDA3NzM0MTA2IyMj"
77 | },
78 | "showQuickUse2": true,
79 | "showSVGs": true,
80 | "fontHostingName": false
81 | }
82 | }
--------------------------------------------------------------------------------
/simditor/static/simditor/images/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/simditor/static/simditor/images/image.png
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/hotkeys.js:
--------------------------------------------------------------------------------
1 | (function (root, factory) {
2 | if (typeof define === 'function' && define.amd) {
3 | // AMD. Register as an anonymous module unless amdModuleId is set
4 | define('simple-hotkeys', ["jquery","simple-module"], function ($, SimpleModule) {
5 | return (root['hotkeys'] = factory($, SimpleModule));
6 | });
7 | } else if (typeof exports === 'object') {
8 | // Node. Does not work with strict CommonJS, but
9 | // only CommonJS-like environments that support module.exports,
10 | // like Node.
11 | module.exports = factory(require("jquery"),require("simple-module"));
12 | } else {
13 | root.simple = root.simple || {};
14 | root.simple['hotkeys'] = factory(jQuery,SimpleModule);
15 | }
16 | }(this, function ($, SimpleModule) {
17 |
18 | var Hotkeys, hotkeys,
19 | extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
20 | hasProp = {}.hasOwnProperty;
21 |
22 | Hotkeys = (function(superClass) {
23 | extend(Hotkeys, superClass);
24 |
25 | function Hotkeys() {
26 | return Hotkeys.__super__.constructor.apply(this, arguments);
27 | }
28 |
29 | Hotkeys.count = 0;
30 |
31 | Hotkeys.keyNameMap = {
32 | 8: "Backspace",
33 | 9: "Tab",
34 | 13: "Enter",
35 | 16: "Shift",
36 | 17: "Control",
37 | 18: "Alt",
38 | 19: "Pause",
39 | 20: "CapsLock",
40 | 27: "Esc",
41 | 32: "Spacebar",
42 | 33: "PageUp",
43 | 34: "PageDown",
44 | 35: "End",
45 | 36: "Home",
46 | 37: "Left",
47 | 38: "Up",
48 | 39: "Right",
49 | 40: "Down",
50 | 45: "Insert",
51 | 46: "Del",
52 | 91: "Meta",
53 | 93: "Meta",
54 | 48: "0",
55 | 49: "1",
56 | 50: "2",
57 | 51: "3",
58 | 52: "4",
59 | 53: "5",
60 | 54: "6",
61 | 55: "7",
62 | 56: "8",
63 | 57: "9",
64 | 65: "A",
65 | 66: "B",
66 | 67: "C",
67 | 68: "D",
68 | 69: "E",
69 | 70: "F",
70 | 71: "G",
71 | 72: "H",
72 | 73: "I",
73 | 74: "J",
74 | 75: "K",
75 | 76: "L",
76 | 77: "M",
77 | 78: "N",
78 | 79: "O",
79 | 80: "P",
80 | 81: "Q",
81 | 82: "R",
82 | 83: "S",
83 | 84: "T",
84 | 85: "U",
85 | 86: "V",
86 | 87: "W",
87 | 88: "X",
88 | 89: "Y",
89 | 90: "Z",
90 | 96: "0",
91 | 97: "1",
92 | 98: "2",
93 | 99: "3",
94 | 100: "4",
95 | 101: "5",
96 | 102: "6",
97 | 103: "7",
98 | 104: "8",
99 | 105: "9",
100 | 106: "Multiply",
101 | 107: "Add",
102 | 109: "Subtract",
103 | 110: "Decimal",
104 | 111: "Divide",
105 | 112: "F1",
106 | 113: "F2",
107 | 114: "F3",
108 | 115: "F4",
109 | 116: "F5",
110 | 117: "F6",
111 | 118: "F7",
112 | 119: "F8",
113 | 120: "F9",
114 | 121: "F10",
115 | 122: "F11",
116 | 123: "F12",
117 | 124: "F13",
118 | 125: "F14",
119 | 126: "F15",
120 | 127: "F16",
121 | 128: "F17",
122 | 129: "F18",
123 | 130: "F19",
124 | 131: "F20",
125 | 132: "F21",
126 | 133: "F22",
127 | 134: "F23",
128 | 135: "F24",
129 | 59: ";",
130 | 61: "=",
131 | 186: ";",
132 | 187: "=",
133 | 188: ",",
134 | 190: ".",
135 | 191: "/",
136 | 192: "`",
137 | 219: "[",
138 | 220: "\\",
139 | 221: "]",
140 | 222: "'"
141 | };
142 |
143 | Hotkeys.aliases = {
144 | "escape": "esc",
145 | "delete": "del",
146 | "return": "enter",
147 | "ctrl": "control",
148 | "space": "spacebar",
149 | "ins": "insert",
150 | "cmd": "meta",
151 | "command": "meta",
152 | "wins": "meta",
153 | "windows": "meta"
154 | };
155 |
156 | Hotkeys.normalize = function(shortcut) {
157 | var i, j, key, keyname, keys, len;
158 | keys = shortcut.toLowerCase().replace(/\s+/gi, "").split("+");
159 | for (i = j = 0, len = keys.length; j < len; i = ++j) {
160 | key = keys[i];
161 | keys[i] = this.aliases[key] || key;
162 | }
163 | keyname = keys.pop();
164 | keys.sort().push(keyname);
165 | return keys.join("_");
166 | };
167 |
168 | Hotkeys.prototype.opts = {
169 | el: document
170 | };
171 |
172 | Hotkeys.prototype._init = function() {
173 | this.id = ++this.constructor.count;
174 | this._map = {};
175 | this._delegate = typeof this.opts.el === "string" ? document : this.opts.el;
176 | return $(this._delegate).on("keydown.simple-hotkeys-" + this.id, this.opts.el, (function(_this) {
177 | return function(e) {
178 | var ref;
179 | return (ref = _this._getHander(e)) != null ? ref.call(_this, e) : void 0;
180 | };
181 | })(this));
182 | };
183 |
184 | Hotkeys.prototype._getHander = function(e) {
185 | var keyname, shortcut;
186 | if (!(keyname = this.constructor.keyNameMap[e.which])) {
187 | return;
188 | }
189 | shortcut = "";
190 | if (e.altKey) {
191 | shortcut += "alt_";
192 | }
193 | if (e.ctrlKey) {
194 | shortcut += "control_";
195 | }
196 | if (e.metaKey) {
197 | shortcut += "meta_";
198 | }
199 | if (e.shiftKey) {
200 | shortcut += "shift_";
201 | }
202 | shortcut += keyname.toLowerCase();
203 | return this._map[shortcut];
204 | };
205 |
206 | Hotkeys.prototype.respondTo = function(subject) {
207 | if (typeof subject === 'string') {
208 | return this._map[this.constructor.normalize(subject)] != null;
209 | } else {
210 | return this._getHander(subject) != null;
211 | }
212 | };
213 |
214 | Hotkeys.prototype.add = function(shortcut, handler) {
215 | this._map[this.constructor.normalize(shortcut)] = handler;
216 | return this;
217 | };
218 |
219 | Hotkeys.prototype.remove = function(shortcut) {
220 | delete this._map[this.constructor.normalize(shortcut)];
221 | return this;
222 | };
223 |
224 | Hotkeys.prototype.destroy = function() {
225 | $(this._delegate).off(".simple-hotkeys-" + this.id);
226 | this._map = {};
227 | return this;
228 | };
229 |
230 | return Hotkeys;
231 |
232 | })(SimpleModule);
233 |
234 | hotkeys = function(opts) {
235 | return new Hotkeys(opts);
236 | };
237 |
238 | return hotkeys;
239 |
240 | }));
241 |
242 |
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/hotkeys.min.js:
--------------------------------------------------------------------------------
1 | !function(a,b){"function"==typeof define&&define.amd?
2 | // AMD. Register as an anonymous module unless amdModuleId is set
3 | define("simple-hotkeys",["jquery","simple-module"],function(c,d){return a.hotkeys=b(c,d)}):"object"==typeof exports?
4 | // Node. Does not work with strict CommonJS, but
5 | // only CommonJS-like environments that support module.exports,
6 | // like Node.
7 | module.exports=b(require("jquery"),require("simple-module")):(a.simple=a.simple||{},a.simple.hotkeys=b(jQuery,SimpleModule))}(this,function(a,b){var c,d,e=function(a,b){function c(){this.constructor=a}for(var d in b)f.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},f={}.hasOwnProperty;return c=function(b){function c(){return c.__super__.constructor.apply(this,arguments)}return e(c,b),c.count=0,c.keyNameMap={8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Spacebar",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",45:"Insert",46:"Del",91:"Meta",93:"Meta",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",65:"A",66:"B",67:"C",68:"D",69:"E",70:"F",71:"G",72:"H",73:"I",74:"J",75:"K",76:"L",77:"M",78:"N",79:"O",80:"P",81:"Q",82:"R",83:"S",84:"T",85:"U",86:"V",87:"W",88:"X",89:"Y",90:"Z",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"Multiply",107:"Add",109:"Subtract",110:"Decimal",111:"Divide",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",124:"F13",125:"F14",126:"F15",127:"F16",128:"F17",129:"F18",130:"F19",131:"F20",132:"F21",133:"F22",134:"F23",135:"F24",59:";",61:"=",186:";",187:"=",188:",",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},c.aliases={escape:"esc","delete":"del","return":"enter",ctrl:"control",space:"spacebar",ins:"insert",cmd:"meta",command:"meta",wins:"meta",windows:"meta"},c.normalize=function(a){var b,c,d,e,f,g;for(f=a.toLowerCase().replace(/\s+/gi,"").split("+"),b=c=0,g=f.length;g>c;b=++c)d=f[b],f[b]=this.aliases[d]||d;return e=f.pop(),f.sort().push(e),f.join("_")},c.prototype.opts={el:document},c.prototype._init=function(){return this.id=++this.constructor.count,this._map={},this._delegate="string"==typeof this.opts.el?document:this.opts.el,a(this._delegate).on("keydown.simple-hotkeys-"+this.id,this.opts.el,function(a){return function(b){var c;return null!=(c=a._getHander(b))?c.call(a,b):void 0}}(this))},c.prototype._getHander=function(a){var b,c;if(b=this.constructor.keyNameMap[a.which])return c="",a.altKey&&(c+="alt_"),a.ctrlKey&&(c+="control_"),a.metaKey&&(c+="meta_"),a.shiftKey&&(c+="shift_"),c+=b.toLowerCase(),this._map[c]},c.prototype.respondTo=function(a){return"string"==typeof a?null!=this._map[this.constructor.normalize(a)]:null!=this._getHander(a)},c.prototype.add=function(a,b){return this._map[this.constructor.normalize(a)]=b,this},c.prototype.remove=function(a){return delete this._map[this.constructor.normalize(a)],this},c.prototype.destroy=function(){return a(this._delegate).off(".simple-hotkeys-"+this.id),this._map={},this},c}(b),d=function(a){return new c(a)}});
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/marked.min.js:
--------------------------------------------------------------------------------
1 | (function(){function e(e){this.tokens=[],this.tokens.links={},this.options=e||a.defaults,this.rules=p.normal,this.options.gfm&&(this.options.tables?this.rules=p.tables:this.rules=p.gfm)}function t(e,t){if(this.options=t||a.defaults,this.links=e,this.rules=u.normal,this.renderer=this.options.renderer||new n,this.renderer.options=this.options,!this.links)throw new Error("Tokens array requires a `links` property.");this.options.gfm?this.options.breaks?this.rules=u.breaks:this.rules=u.gfm:this.options.pedantic&&(this.rules=u.pedantic)}function n(e){this.options=e||{}}function r(e){this.tokens=[],this.token=null,this.options=e||a.defaults,this.options.renderer=this.options.renderer||new n,this.renderer=this.options.renderer,this.renderer.options=this.options}function s(e,t){return e.replace(t?/&/g:/&(?!#?\w+;)/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function i(e){return e.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g,function(e,t){return t=t.toLowerCase(),"colon"===t?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}function l(e,t){return e=e.source,t=t||"",function n(r,s){return r?(s=s.source||s,s=s.replace(/(^|[^\[])\^/g,"$1"),e=e.replace(r,s),n):new RegExp(e,t)}}function o(){}function h(e){for(var t,n,r=1;rAn error occured:"+s(c.message+"",!0)+"
";throw c}}var p={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:o,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:o,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:o,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};p.bullet=/(?:[*+-]|\d+\.)/,p.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,p.item=l(p.item,"gm")(/bull/g,p.bullet)(),p.list=l(p.list)(/bull/g,p.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+p.def.source+")")(),p.blockquote=l(p.blockquote)("def",p.def)(),p._tag="(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b",p.html=l(p.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,p._tag)(),p.paragraph=l(p.paragraph)("hr",p.hr)("heading",p.heading)("lheading",p.lheading)("blockquote",p.blockquote)("tag","<"+p._tag)("def",p.def)(),p.normal=h({},p),p.gfm=h({},p.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),p.gfm.paragraph=l(p.paragraph)("(?!","(?!"+p.gfm.fences.source.replace("\\1","\\2")+"|"+p.list.source.replace("\\1","\\3")+"|")(),p.tables=h({},p.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/}),e.rules=p,e.lex=function(t,n){var r=new e(n);return r.lex(t)},e.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},e.prototype.token=function(e,t,n){for(var r,s,i,l,o,h,a,u,c,e=e.replace(/^ +$/gm,"");e;)if((i=this.rules.newline.exec(e))&&(e=e.substring(i[0].length),i[0].length>1&&this.tokens.push({type:"space"})),i=this.rules.code.exec(e))e=e.substring(i[0].length),i=i[0].replace(/^ {4}/gm,""),this.tokens.push({type:"code",text:this.options.pedantic?i:i.replace(/\n+$/,"")});else if(i=this.rules.fences.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"code",lang:i[2],text:i[3]||""});else if(i=this.rules.heading.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"heading",depth:i[1].length,text:i[2]});else if(t&&(i=this.rules.nptable.exec(e))){for(e=e.substring(i[0].length),h={type:"table",header:i[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3].replace(/\n$/,"").split("\n")},u=0;u ?/gm,""),this.token(i,t,!0),this.tokens.push({type:"blockquote_end"});else if(i=this.rules.list.exec(e)){for(e=e.substring(i[0].length),l=i[2],this.tokens.push({type:"list_start",ordered:l.length>1}),i=i[0].match(this.rules.item),r=!1,c=i.length,u=0;c>u;u++)h=i[u],a=h.length,h=h.replace(/^ *([*+-]|\d+\.) +/,""),~h.indexOf("\n ")&&(a-=h.length,h=this.options.pedantic?h.replace(/^ {1,4}/gm,""):h.replace(new RegExp("^ {1,"+a+"}","gm"),"")),this.options.smartLists&&u!==c-1&&(o=p.bullet.exec(i[u+1])[0],l===o||l.length>1&&o.length>1||(e=i.slice(u+1).join("\n")+e,u=c-1)),s=r||/\n\n(?!\s*$)/.test(h),u!==c-1&&(r="\n"===h.charAt(h.length-1),s||(s=r)),this.tokens.push({type:s?"loose_item_start":"list_item_start"}),this.token(h,!1,n),this.tokens.push({type:"list_item_end"});this.tokens.push({type:"list_end"})}else if(i=this.rules.html.exec(e))e=e.substring(i[0].length),this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&("pre"===i[1]||"script"===i[1]||"style"===i[1]),text:i[0]});else if(!n&&t&&(i=this.rules.def.exec(e)))e=e.substring(i[0].length),this.tokens.links[i[1].toLowerCase()]={href:i[2],title:i[3]};else if(t&&(i=this.rules.table.exec(e))){for(e=e.substring(i[0].length),h={type:"table",header:i[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3].replace(/(?: *\| *)?\n$/,"").split("\n")},u=0;u])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:o,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:o,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/,u.link=l(u.link)("inside",u._inside)("href",u._href)(),u.reflink=l(u.reflink)("inside",u._inside)(),u.normal=h({},u),u.pedantic=h({},u.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/}),u.gfm=h({},u.normal,{escape:l(u.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:l(u.text)("]|","~]|")("|","|https?://|")()}),u.breaks=h({},u.gfm,{br:l(u.br)("{2,}","*")(),text:l(u.gfm.text)("{2,}","*")()}),t.rules=u,t.output=function(e,n,r){var s=new t(n,r);return s.output(e)},t.prototype.output=function(e){for(var t,n,r,i,l="";e;)if(i=this.rules.escape.exec(e))e=e.substring(i[0].length),l+=i[1];else if(i=this.rules.autolink.exec(e))e=e.substring(i[0].length),"@"===i[2]?(n=":"===i[1].charAt(6)?this.mangle(i[1].substring(7)):this.mangle(i[1]),r=this.mangle("mailto:")+n):(n=s(i[1]),r=n),l+=this.renderer.link(r,null,n);else if(this.inLink||!(i=this.rules.url.exec(e))){if(i=this.rules.tag.exec(e))!this.inLink&&/^/i.test(i[0])&&(this.inLink=!1),e=e.substring(i[0].length),l+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(i[0]):s(i[0]):i[0];else if(i=this.rules.link.exec(e))e=e.substring(i[0].length),this.inLink=!0,l+=this.outputLink(i,{href:i[2],title:i[3]}),this.inLink=!1;else if((i=this.rules.reflink.exec(e))||(i=this.rules.nolink.exec(e))){if(e=e.substring(i[0].length),t=(i[2]||i[1]).replace(/\s+/g," "),t=this.links[t.toLowerCase()],!t||!t.href){l+=i[0].charAt(0),e=i[0].substring(1)+e;continue}this.inLink=!0,l+=this.outputLink(i,t),this.inLink=!1}else if(i=this.rules.strong.exec(e))e=e.substring(i[0].length),l+=this.renderer.strong(this.output(i[2]||i[1]));else if(i=this.rules.em.exec(e))e=e.substring(i[0].length),l+=this.renderer.em(this.output(i[2]||i[1]));else if(i=this.rules.code.exec(e))e=e.substring(i[0].length),l+=this.renderer.codespan(s(i[2],!0));else if(i=this.rules.br.exec(e))e=e.substring(i[0].length),l+=this.renderer.br();else if(i=this.rules.del.exec(e))e=e.substring(i[0].length),l+=this.renderer.del(this.output(i[1]));else if(i=this.rules.text.exec(e))e=e.substring(i[0].length),l+=this.renderer.text(s(this.smartypants(i[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else e=e.substring(i[0].length),n=s(i[1]),r=n,l+=this.renderer.link(r,null,n);return l},t.prototype.outputLink=function(e,t){var n=s(t.href),r=t.title?s(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,s(e[1]))},t.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014\/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014\/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},t.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,s=0;r>s;s++)t=e.charCodeAt(s),Math.random()>.5&&(t="x"+t.toString(16)),n+=""+t+";";return n},n.prototype.code=function(e,t,n){if(this.options.highlight){var r=this.options.highlight(e,t);null!=r&&r!==e&&(n=!0,e=r)}return t?''+(n?e:s(e,!0))+"\n
\n":""+(n?e:s(e,!0))+"\n
"},n.prototype.blockquote=function(e){return"\n"+e+"
\n"},n.prototype.html=function(e){return e},n.prototype.heading=function(e,t,n){return"\n"},n.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"},n.prototype.list=function(e,t){var n=t?"ol":"ul";return"<"+n+">\n"+e+""+n+">\n"},n.prototype.listitem=function(e){return""+e+"\n"},n.prototype.paragraph=function(e){return""+e+"
\n"},n.prototype.table=function(e,t){return"\n"},n.prototype.tablerow=function(e){return"\n"+e+"
\n"},n.prototype.tablecell=function(e,t){var n=t.header?"th":"td",r=t.align?"<"+n+' style="text-align:'+t.align+'">':"<"+n+">";return r+e+""+n+">\n"},n.prototype.strong=function(e){return""+e+""},n.prototype.em=function(e){return""+e+""},n.prototype.codespan=function(e){return""+e+"
"},n.prototype.br=function(){return this.options.xhtml?"
":"
"},n.prototype.del=function(e){return""+e+""},n.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(i(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(s){return""}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:"))return""}var l='"+n+""},n.prototype.image=function(e,t,n){var r='
":">"},n.prototype.text=function(e){return e},r.parse=function(e,t,n){var s=new r(t,n);return s.parse(e)},r.prototype.parse=function(e){this.inline=new t(e.links,this.options,this.renderer),this.tokens=e.reverse();for(var n="";this.next();)n+=this.tok();return n},r.prototype.next=function(){return this.token=this.tokens.pop()},r.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},r.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},r.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,r,s,i="",l="";for(n="",e=0;e 0)) {
148 | return result;
149 | }
150 | result = result.replace(/([^%]|^)%(?:(\d+)\$)?s/g, function(p0, p, position) {
151 | if (position) {
152 | return p + args[parseInt(position) - 1];
153 | } else {
154 | return p + args.shift();
155 | }
156 | });
157 | return result.replace(/%%s/g, '%s');
158 | };
159 |
160 | Module.i18n = {
161 | 'zh-CN': {}
162 | };
163 |
164 | Module.locale = 'zh-CN';
165 |
166 | return Module;
167 |
168 | })();
169 |
170 | return Module;
171 |
172 | }));
173 |
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/module.min.js:
--------------------------------------------------------------------------------
1 | !function(a,b){"function"==typeof define&&define.amd?
2 | // AMD. Register as an anonymous module unless amdModuleId is set
3 | define("simple-module",["jquery"],function(c){return a.Module=b(c)}):"object"==typeof exports?module.exports=b(require("jquery")):a.SimpleModule=b(jQuery)}(this,function(a){var b,c=[].slice;return b=function(){function b(b){var c,d,e,f,g,h,i;if(this.opts=a.extend({},this.opts,b),(c=this.constructor)._connectedClasses||(c._connectedClasses=[]),g=function(){var a,b,c,e;for(c=this.constructor._connectedClasses,e=[],a=0,b=c.length;b>a;a++)d=c[a],i=d.pluginName.charAt(0).toLowerCase()+d.pluginName.slice(1),d.prototype._connected&&(d.prototype._module=this),e.push(this[i]=new d);return e}.call(this),this._connected)this.opts=a.extend({},this.opts,this._module.opts);else for(this._init(),e=0,h=g.length;h>e;e++)f=g[e],"function"==typeof f._init&&f._init();this.trigger("initialized")}return b.extend=function(a){var b,c,d;if(null!=a&&"object"==typeof a){for(b in a)d=a[b],"included"!==b&&"extended"!==b&&(this[b]=d);return null!=(c=a.extended)?c.call(this):void 0}},b.include=function(a){var b,c,d;if(null!=a&&"object"==typeof a){for(b in a)d=a[b],"included"!==b&&"extended"!==b&&(this.prototype[b]=d);return null!=(c=a.included)?c.call(this):void 0}},b.connect=function(a){if("function"==typeof a){if(!a.pluginName)throw new Error("Module.connect: cannot connect plugin without pluginName");return a.prototype._connected=!0,this._connectedClasses||(this._connectedClasses=[]),this._connectedClasses.push(a),a.pluginName?this[a.pluginName]=a:void 0}},b.prototype.opts={},b.prototype._init=function(){},b.prototype.on=function(){var b,d;return b=1<=arguments.length?c.call(arguments,0):[],(d=a(this)).on.apply(d,b),this},b.prototype.one=function(){var b,d;return b=1<=arguments.length?c.call(arguments,0):[],(d=a(this)).one.apply(d,b),this},b.prototype.off=function(){var b,d;return b=1<=arguments.length?c.call(arguments,0):[],(d=a(this)).off.apply(d,b),this},b.prototype.trigger=function(){var b,d;return b=1<=arguments.length?c.call(arguments,0):[],(d=a(this)).trigger.apply(d,b),this},b.prototype.triggerHandler=function(){var b,d;return b=1<=arguments.length?c.call(arguments,0):[],(d=a(this)).triggerHandler.apply(d,b)},b.prototype._t=function(){var a,b;return a=1<=arguments.length?c.call(arguments,0):[],(b=this.constructor)._t.apply(b,a)},b._t=function(){var a,b,d,e;return b=arguments[0],a=2<=arguments.length?c.call(arguments,1):[],e=(null!=(d=this.i18n[this.locale])?d[b]:void 0)||"",a.length>0?(e=e.replace(/([^%]|^)%(?:(\d+)\$)?s/g,function(b,c,d){return d?c+a[parseInt(d)-1]:c+a.shift()}),e.replace(/%%s/g,"%s")):e},b.i18n={"zh-CN":{}},b.locale="zh-CN",b}()});
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/simditor-checklist.js:
--------------------------------------------------------------------------------
1 | (function (root, factory) {
2 | if (typeof define === 'function' && define.amd) {
3 | // AMD. Register as an anonymous module unless amdModuleId is set
4 | define('simditor-checklist', ["jquery","simditor"], function (a0,b1) {
5 | return (root['ChecklistButton'] = factory(a0,b1));
6 | });
7 | } else if (typeof exports === 'object') {
8 | // Node. Does not work with strict CommonJS, but
9 | // only CommonJS-like environments that support module.exports,
10 | // like Node.
11 | module.exports = factory(require("jquery"),require("simditor"));
12 | } else {
13 | root['ChecklistButton'] = factory(jQuery,Simditor);
14 | }
15 | }(this, function ($, Simditor) {
16 |
17 | var ChecklistButton,
18 | extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
19 | hasProp = {}.hasOwnProperty,
20 | slice = [].slice;
21 |
22 | ChecklistButton = (function(superClass) {
23 | extend(ChecklistButton, superClass);
24 |
25 | ChecklistButton.prototype.type = 'ul.simditor-checklist';
26 |
27 | ChecklistButton.prototype.name = 'checklist';
28 |
29 | ChecklistButton.prototype.icon = 'checklist';
30 |
31 | ChecklistButton.prototype.htmlTag = 'li';
32 |
33 | ChecklistButton.prototype.disableTag = 'pre, table';
34 |
35 | function ChecklistButton() {
36 | var args;
37 | args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
38 | ChecklistButton.__super__.constructor.apply(this, args);
39 | if ('input' && $.inArray('input', this.editor.formatter._allowedTags) < 0) {
40 | this.editor.formatter._allowedTags.push('input');
41 | }
42 | $.extend(this.editor.formatter._allowedAttributes, {
43 | input: ['type', 'checked']
44 | });
45 | }
46 |
47 | ChecklistButton.prototype._init = function() {
48 | ChecklistButton.__super__._init.call(this);
49 | this.editor.on('decorate', (function(_this) {
50 | return function(e, $el) {
51 | return $el.find('ul > li input[type=checkbox]').each(function(i, checkbox) {
52 | return _this._decorate($(checkbox));
53 | });
54 | };
55 | })(this));
56 | this.editor.on('undecorate', (function(_this) {
57 | return function(e, $el) {
58 | return $el.find('.simditor-checklist > li').each(function(i, node) {
59 | return _this._undecorate($(node));
60 | });
61 | };
62 | })(this));
63 | this.editor.body.on('click', '.simditor-checklist > li', (function(_this) {
64 | return function(e) {
65 | var $node, range;
66 | e.preventDefault();
67 | e.stopPropagation();
68 | $node = $(e.currentTarget);
69 | range = document.createRange();
70 | _this.editor.selection.save();
71 | range.setStart($node[0], 0);
72 | range.setEnd($node[0], _this.editor.util.getNodeLength($node[0]));
73 | _this.editor.selection.range(range);
74 | document.execCommand('strikethrough');
75 | $node.attr('checked', !$node.attr('checked'));
76 | _this.editor.selection.restore();
77 | return _this.editor.trigger('valuechanged');
78 | };
79 | })(this));
80 | return this.editor.keystroke.add('13', 'li', (function(_this) {
81 | return function(e, $node) {
82 | return setTimeout(function() {
83 | var $li;
84 | $li = _this.editor.selection.blockNodes().last().next();
85 | if ($li.length) {
86 | $li[0].removeAttribute('checked');
87 | if (document.queryCommandState('strikethrough')) {
88 | return document.execCommand('strikethrough');
89 | }
90 | }
91 | }, 0);
92 | };
93 | })(this));
94 | };
95 |
96 | ChecklistButton.prototype._status = function() {
97 | var $node;
98 | ChecklistButton.__super__._status.call(this);
99 | $node = this.editor.selection.rootNodes();
100 | if ($node.is('.simditor-checklist')) {
101 | this.editor.toolbar.findButton('ul').setActive(false);
102 | this.editor.toolbar.findButton('ol').setActive(false);
103 | this.editor.toolbar.findButton('ul').setDisabled(true);
104 | return this.editor.toolbar.findButton('ol').setDisabled(true);
105 | } else {
106 | return this.editor.toolbar.findButton('checklist').setActive(false);
107 | }
108 | };
109 |
110 | ChecklistButton.prototype.command = function(param) {
111 | var $list, $rootNodes;
112 | $rootNodes = this.editor.selection.blockNodes();
113 | this.editor.selection.save();
114 | $list = null;
115 | $rootNodes.each((function(_this) {
116 | return function(i, node) {
117 | var $node;
118 | $node = $(node);
119 | if ($node.is('blockquote, li') || $node.is(_this.disableTag) || !$.contains(document, node)) {
120 | return;
121 | }
122 | if ($node.is('.simditor-checklist')) {
123 | $node.children('li').each(function(i, li) {
124 | var $childList, $li;
125 | $li = $(li);
126 | $childList = $li.children('ul, ol').insertAfter($node);
127 | return $('').append($(li).html() || _this.editor.util.phBr).insertBefore($node);
128 | });
129 | return $node.remove();
130 | } else if ($node.is('ul, ol')) {
131 | return $('').append($node.contents()).replaceAll($node);
132 | } else if ($list && $node.prev().is($list)) {
133 | $('').append($node.html() || _this.editor.util.phBr).appendTo($list);
134 | return $node.remove();
135 | } else {
136 | $list = $('');
137 | $list.find('li').append($node.html() || _this.editor.util.phBr);
138 | return $list.replaceAll($node);
139 | }
140 | };
141 | })(this));
142 | this.editor.selection.restore();
143 | return this.editor.trigger('valuechanged');
144 | };
145 |
146 | ChecklistButton.prototype._decorate = function($checkbox) {
147 | var $node, checked;
148 | checked = !!$checkbox.attr('checked');
149 | $node = $checkbox.closest('li');
150 | $checkbox.remove();
151 | $node.attr('checked', checked);
152 | return $node.closest('ul').addClass('simditor-checklist');
153 | };
154 |
155 | ChecklistButton.prototype._undecorate = function($node) {
156 | var $checkbox, checked;
157 | checked = !!$node.attr('checked');
158 | $checkbox = $('').attr('checked', checked);
159 | return $node.attr('checked', '').prepend($checkbox);
160 | };
161 |
162 | return ChecklistButton;
163 |
164 | })(Simditor.Button);
165 |
166 | Simditor.Toolbar.addButton(ChecklistButton);
167 |
168 | return ChecklistButton;
169 |
170 | }));
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/simditor-checklist.min.js:
--------------------------------------------------------------------------------
1 | (function(root,factory){if(typeof define==="function"&&define.amd){define("simditor-checklist",["jquery","simditor"],function(a0,b1){return(root["ChecklistButton"]=factory(a0,b1))})}else{if(typeof exports==="object"){module.exports=factory(require("jquery"),require("simditor"))}else{root["ChecklistButton"]=factory(jQuery,Simditor)}}}(this,function($,Simditor){var ChecklistButton,extend=function(child,parent){for(var key in parent){if(hasProp.call(parent,key)){child[key]=parent[key]}}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor();child.__super__=parent.prototype;return child},hasProp={}.hasOwnProperty,slice=[].slice;ChecklistButton=(function(superClass){extend(ChecklistButton,superClass);ChecklistButton.prototype.type="ul.simditor-checklist";ChecklistButton.prototype.name="checklist";ChecklistButton.prototype.icon="checklist";ChecklistButton.prototype.htmlTag="li";ChecklistButton.prototype.disableTag="pre, table";function ChecklistButton(){var args;args=1<=arguments.length?slice.call(arguments,0):[];ChecklistButton.__super__.constructor.apply(this,args);if("input"&&$.inArray("input",this.editor.formatter._allowedTags)<0){this.editor.formatter._allowedTags.push("input")}$.extend(this.editor.formatter._allowedAttributes,{input:["type","checked"]})}ChecklistButton.prototype._init=function(){ChecklistButton.__super__._init.call(this);this.editor.on("decorate",(function(_this){return function(e,$el){return $el.find("ul > li input[type=checkbox]").each(function(i,checkbox){return _this._decorate($(checkbox))})}})(this));this.editor.on("undecorate",(function(_this){return function(e,$el){return $el.find(".simditor-checklist > li").each(function(i,node){return _this._undecorate($(node))})}})(this));this.editor.body.on("click",".simditor-checklist > li",(function(_this){return function(e){var $node,range;e.preventDefault();e.stopPropagation();$node=$(e.currentTarget);range=document.createRange();_this.editor.selection.save();range.setStart($node[0],0);range.setEnd($node[0],_this.editor.util.getNodeLength($node[0]));_this.editor.selection.range(range);document.execCommand("strikethrough");$node.attr("checked",!$node.attr("checked"));_this.editor.selection.restore();return _this.editor.trigger("valuechanged")}})(this));return this.editor.keystroke.add("13","li",(function(_this){return function(e,$node){return setTimeout(function(){var $li;$li=_this.editor.selection.blockNodes().last().next();if($li.length){$li[0].removeAttribute("checked");if(document.queryCommandState("strikethrough")){return document.execCommand("strikethrough")}}},0)}})(this))};ChecklistButton.prototype._status=function(){var $node;ChecklistButton.__super__._status.call(this);$node=this.editor.selection.rootNodes();if($node.is(".simditor-checklist")){this.editor.toolbar.findButton("ul").setActive(false);this.editor.toolbar.findButton("ol").setActive(false);this.editor.toolbar.findButton("ul").setDisabled(true);return this.editor.toolbar.findButton("ol").setDisabled(true)}else{return this.editor.toolbar.findButton("checklist").setActive(false)}};ChecklistButton.prototype.command=function(param){var $list,$rootNodes;$rootNodes=this.editor.selection.blockNodes();this.editor.selection.save();$list=null;$rootNodes.each((function(_this){return function(i,node){var $node;$node=$(node);if($node.is("blockquote, li")||$node.is(_this.disableTag)||!$.contains(document,node)){return}if($node.is(".simditor-checklist")){$node.children("li").each(function(i,li){var $childList,$li;$li=$(li);$childList=$li.children("ul, ol").insertAfter($node);return $("").append($(li).html()||_this.editor.util.phBr).insertBefore($node)});return $node.remove()}else{if($node.is("ul, ol")){return $('').append($node.contents()).replaceAll($node)}else{if($list&&$node.prev().is($list)){$("").append($node.html()||_this.editor.util.phBr).appendTo($list);return $node.remove()}else{$list=$('');$list.find("li").append($node.html()||_this.editor.util.phBr);return $list.replaceAll($node)}}}}})(this));this.editor.selection.restore();return this.editor.trigger("valuechanged")};ChecklistButton.prototype._decorate=function($checkbox){var $node,checked;checked=!!$checkbox.attr("checked");$node=$checkbox.closest("li");$checkbox.remove();$node.attr("checked",checked);return $node.closest("ul").addClass("simditor-checklist")};ChecklistButton.prototype._undecorate=function($node){var $checkbox,checked;checked=!!$node.attr("checked");$checkbox=$('').attr("checked",checked);return $node.attr("checked","").prepend($checkbox)};return ChecklistButton})(Simditor.Button);Simditor.Toolbar.addButton(ChecklistButton);return ChecklistButton}));
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/simditor-dropzone.js:
--------------------------------------------------------------------------------
1 | (function (root, factory) {
2 | if (typeof define === 'function' && define.amd) {
3 | // AMD. Register as an anonymous module.
4 | define(["jquery",
5 | "simple-module",
6 | "simditor"], function ($, SimpleModule, Simditor) {
7 | return (root.returnExportsGlobal = factory($, SimpleModule, Simditor));
8 | });
9 | } else if (typeof exports === 'object') {
10 | // Node. Does not work with strict CommonJS, but
11 | // only CommonJS-like enviroments that support module.exports,
12 | // like Node.
13 | module.exports = factory(require("jquery"),
14 | require("simple-module"),
15 | require("simditor"));
16 | } else {
17 | root['Simditor'] = factory(jQuery,
18 | SimpleModule,
19 | Simditor);
20 | }
21 | }(this, function ($, SimpleModule, Simditor) {
22 |
23 | var Dropzone,
24 | __hasProp = {}.hasOwnProperty,
25 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
26 |
27 | Dropzone = (function(_super) {
28 | __extends(Dropzone, _super);
29 |
30 | function Dropzone() {
31 | return Dropzone.__super__.constructor.apply(this, arguments);
32 | }
33 |
34 | Dropzone.pluginName = "Dropzone";
35 |
36 | Dropzone.prototype._entered = 0;
37 |
38 | Dropzone.prototype._init = function() {
39 | this.editor = this._module;
40 | if (this.editor.uploader == null) {
41 | throw new Error("Can't work without 'simple-uploader' module");
42 | return;
43 | }
44 | $(document.body).on("dragover", function(e) {
45 | e.originalEvent.dataTransfer.dropEffect = "none";
46 | return e.preventDefault();
47 | });
48 | $(document.body).on('drop', function(e) {
49 | return e.preventDefault();
50 | });
51 | this.imageBtn = this.editor.toolbar.findButton("image");
52 | return this.editor.body.on("dragover", function(e) {
53 | e.originalEvent.dataTransfer.dropEffect = "copy";
54 | e.stopPropagation();
55 | return e.preventDefault();
56 | }).on("dragenter", (function(_this) {
57 | return function(e) {
58 | if ((_this._entered += 1) === 1) {
59 | _this.show();
60 | }
61 | e.preventDefault();
62 | return e.stopPropagation();
63 | };
64 | })(this)).on("dragleave", (function(_this) {
65 | return function(e) {
66 | if ((_this._entered -= 1) <= 0) {
67 | _this.hide();
68 | }
69 | e.preventDefault();
70 | return e.stopPropagation();
71 | };
72 | })(this)).on("drop", (function(_this) {
73 | return function(e) {
74 | var file, imageFiles, _i, _j, _len, _len1, _ref;
75 | imageFiles = [];
76 | _ref = e.originalEvent.dataTransfer.files;
77 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
78 | file = _ref[_i];
79 | if (!_this.validFile(file)) {
80 | alert("「" + file.name + "]」文件不是图片。");
81 | _this.hide();
82 | return false;
83 | }
84 | imageFiles.push(file);
85 | }
86 | for (_j = 0, _len1 = imageFiles.length; _j < _len1; _j++) {
87 | file = imageFiles[_j];
88 | _this.editor.uploader.upload(file, {
89 | inline: true
90 | });
91 | }
92 | _this.hide();
93 | e.stopPropagation();
94 | return e.preventDefault();
95 | };
96 | })(this));
97 | };
98 |
99 | Dropzone.prototype.show = function() {
100 | return this.imageBtn.setActive(true);
101 | };
102 |
103 | Dropzone.prototype.hide = function() {
104 | this.imageBtn.setActive(false);
105 | return this._entered = 0;
106 | };
107 |
108 | Dropzone.prototype.validFile = function(file) {
109 | return file.type.indexOf("image/") > -1;
110 | };
111 |
112 | return Dropzone;
113 |
114 | })(SimpleModule);
115 |
116 | Simditor.connect(Dropzone);
117 |
118 |
119 | return Simditor;
120 |
121 |
122 | }));
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/simditor-dropzone.min.js:
--------------------------------------------------------------------------------
1 | (function(root,factory){if(typeof define==="function"&&define.amd){define(["jquery","simple-module","simditor"],function($,SimpleModule,Simditor){return(root.returnExportsGlobal=factory($,SimpleModule,Simditor))})}else{if(typeof exports==="object"){module.exports=factory(require("jquery"),require("simple-module"),require("simditor"))}else{root["Simditor"]=factory(jQuery,SimpleModule,Simditor)}}}(this,function($,SimpleModule,Simditor){var Dropzone,__hasProp={}.hasOwnProperty,__extends=function(child,parent){for(var key in parent){if(__hasProp.call(parent,key)){child[key]=parent[key]}}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor();child.__super__=parent.prototype;return child};Dropzone=(function(_super){__extends(Dropzone,_super);function Dropzone(){return Dropzone.__super__.constructor.apply(this,arguments)}Dropzone.pluginName="Dropzone";Dropzone.prototype._entered=0;Dropzone.prototype._init=function(){this.editor=this._module;if(this.editor.uploader==null){throw new Error("Can't work without 'simple-uploader' module");return}$(document.body).on("dragover",function(e){e.originalEvent.dataTransfer.dropEffect="none";return e.preventDefault()});$(document.body).on("drop",function(e){return e.preventDefault()});this.imageBtn=this.editor.toolbar.findButton("image");return this.editor.body.on("dragover",function(e){e.originalEvent.dataTransfer.dropEffect="copy";e.stopPropagation();return e.preventDefault()}).on("dragenter",(function(_this){return function(e){if((_this._entered+=1)===1){_this.show()}e.preventDefault();return e.stopPropagation()}})(this)).on("dragleave",(function(_this){return function(e){if((_this._entered-=1)<=0){_this.hide()}e.preventDefault();return e.stopPropagation()}})(this)).on("drop",(function(_this){return function(e){var file,imageFiles,_i,_j,_len,_len1,_ref;imageFiles=[];_ref=e.originalEvent.dataTransfer.files;for(_i=0,_len=_ref.length;_i<_len;_i++){file=_ref[_i];if(!_this.validFile(file)){alert("「"+file.name+"]」文件不是图片。");_this.hide();return false}imageFiles.push(file)}for(_j=0,_len1=imageFiles.length;_j<_len1;_j++){file=imageFiles[_j];_this.editor.uploader.upload(file,{inline:true})}_this.hide();e.stopPropagation();return e.preventDefault()}})(this))};Dropzone.prototype.show=function(){return this.imageBtn.setActive(true)};Dropzone.prototype.hide=function(){this.imageBtn.setActive(false);return this._entered=0};Dropzone.prototype.validFile=function(file){return file.type.indexOf("image/")>-1};return Dropzone})(SimpleModule);Simditor.connect(Dropzone);return Simditor}));
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/simditor-fullscreen.js:
--------------------------------------------------------------------------------
1 | (function (root, factory) {
2 | if (typeof define === 'function' && define.amd) {
3 | // AMD. Register as an anonymous module unless amdModuleId is set
4 | define('simditor-fullscreen', ["jquery","simditor"], function (a0,b1) {
5 | return (root['SimditorFullscreen'] = factory(a0,b1));
6 | });
7 | } else if (typeof exports === 'object') {
8 | // Node. Does not work with strict CommonJS, but
9 | // only CommonJS-like environments that support module.exports,
10 | // like Node.
11 | module.exports = factory(require("jquery"),require("simditor"));
12 | } else {
13 | root['SimditorFullscreen'] = factory(jQuery,Simditor);
14 | }
15 | }(this, function ($, Simditor) {
16 |
17 | var SimditorFullscreen,
18 | extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
19 | hasProp = {}.hasOwnProperty;
20 |
21 | SimditorFullscreen = (function(superClass) {
22 | extend(SimditorFullscreen, superClass);
23 |
24 | function SimditorFullscreen() {
25 | return SimditorFullscreen.__super__.constructor.apply(this, arguments);
26 | }
27 |
28 | SimditorFullscreen.cls = 'simditor-fullscreen';
29 |
30 | SimditorFullscreen.i18n = {
31 | 'zh-CN': {
32 | fullscreen: '全屏'
33 | }
34 | };
35 |
36 | SimditorFullscreen.prototype.name = 'fullscreen';
37 |
38 | SimditorFullscreen.prototype.needFocus = false;
39 |
40 | SimditorFullscreen.prototype.iconClassOf = function() {
41 | return 'icon-fullscreen';
42 | };
43 |
44 | SimditorFullscreen.prototype._init = function() {
45 | SimditorFullscreen.__super__._init.call(this);
46 | this.window = $(window);
47 | this.body = $('body');
48 | this.editable = this.editor.body;
49 | return this.toolbar = this.editor.toolbar.wrapper;
50 | };
51 |
52 | SimditorFullscreen.prototype.status = function() {
53 | return this.setActive(this.body.hasClass(this.constructor.cls));
54 | };
55 |
56 | SimditorFullscreen.prototype.command = function() {
57 | var editablePadding, isFullscreen;
58 | this.body.toggleClass(this.constructor.cls);
59 | isFullscreen = this.body.hasClass(this.constructor.cls);
60 | if (isFullscreen) {
61 | editablePadding = this.editable.outerHeight() - this.editable.height();
62 | this.window.on("resize.simditor-fullscreen-" + this.editor.id, (function(_this) {
63 | return function() {
64 | return _this._resize({
65 | height: _this.window.height() - _this.toolbar.outerHeight() - editablePadding
66 | });
67 | };
68 | })(this)).resize();
69 | } else {
70 | this.window.off("resize.simditor-fullscreen-" + this.editor.id).resize();
71 | this._resize({
72 | height: 'auto'
73 | });
74 | }
75 | return this.setActive(isFullscreen);
76 | };
77 |
78 | SimditorFullscreen.prototype._resize = function(size) {
79 | return this.editable.height(size.height);
80 | };
81 |
82 | return SimditorFullscreen;
83 |
84 | })(Simditor.Button);
85 |
86 | Simditor.Toolbar.addButton(SimditorFullscreen);
87 |
88 | return SimditorFullscreen;
89 |
90 | }));
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/simditor-fullscreen.min.js:
--------------------------------------------------------------------------------
1 | (function(root,factory){if(typeof define==="function"&&define.amd){define("simditor-fullscreen",["jquery","simditor"],function(a0,b1){return(root["SimditorFullscreen"]=factory(a0,b1))})}else{if(typeof exports==="object"){module.exports=factory(require("jquery"),require("simditor"))}else{root["SimditorFullscreen"]=factory(jQuery,Simditor)}}}(this,function($,Simditor){var SimditorFullscreen,extend=function(child,parent){for(var key in parent){if(hasProp.call(parent,key)){child[key]=parent[key]}}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor();child.__super__=parent.prototype;return child},hasProp={}.hasOwnProperty;SimditorFullscreen=(function(superClass){extend(SimditorFullscreen,superClass);function SimditorFullscreen(){return SimditorFullscreen.__super__.constructor.apply(this,arguments)}SimditorFullscreen.cls="simditor-fullscreen";SimditorFullscreen.i18n={"zh-CN":{fullscreen:"全屏"}};SimditorFullscreen.prototype.name="fullscreen";SimditorFullscreen.prototype.needFocus=false;SimditorFullscreen.prototype.iconClassOf=function(){return"icon-fullscreen"};SimditorFullscreen.prototype._init=function(){SimditorFullscreen.__super__._init.call(this);this.window=$(window);this.body=$("body");this.editable=this.editor.body;return this.toolbar=this.editor.toolbar.wrapper};SimditorFullscreen.prototype.status=function(){return this.setActive(this.body.hasClass(this.constructor.cls))};SimditorFullscreen.prototype.command=function(){var editablePadding,isFullscreen;this.body.toggleClass(this.constructor.cls);isFullscreen=this.body.hasClass(this.constructor.cls);if(isFullscreen){editablePadding=this.editable.outerHeight()-this.editable.height();this.window.on("resize.simditor-fullscreen-"+this.editor.id,(function(_this){return function(){return _this._resize({height:_this.window.height()-_this.toolbar.outerHeight()-editablePadding})}})(this)).resize()}else{this.window.off("resize.simditor-fullscreen-"+this.editor.id).resize();this._resize({height:"auto"})}return this.setActive(isFullscreen)};SimditorFullscreen.prototype._resize=function(size){return this.editable.height(size.height)};return SimditorFullscreen})(Simditor.Button);Simditor.Toolbar.addButton(SimditorFullscreen);return SimditorFullscreen}));
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/simditor-markdown.js:
--------------------------------------------------------------------------------
1 | (function (root, factory) {
2 | if (typeof define === 'function' && define.amd) {
3 | // AMD. Register as an anonymous module unless amdModuleId is set
4 | define('simditor-markdown', ["jquery","simditor","to-markdown","marked"], function (a0,b1,c2,d3) {
5 | return (root['SimditorMarkdown'] = factory(a0,b1,c2,d3));
6 | });
7 | } else if (typeof exports === 'object') {
8 | // Node. Does not work with strict CommonJS, but
9 | // only CommonJS-like environments that support module.exports,
10 | // like Node.
11 | module.exports = factory(require("jquery"),require("simditor"),require("to-markdown"),require("marked"));
12 | } else {
13 | root['SimditorMarkdown'] = factory(jQuery,Simditor,toMarkdown,marked);
14 | }
15 | }(this, function ($, Simditor, toMarkdown, marked) {
16 |
17 | var SimditorMarkdown,
18 | extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
19 | hasProp = {}.hasOwnProperty;
20 |
21 | SimditorMarkdown = (function(superClass) {
22 | extend(SimditorMarkdown, superClass);
23 |
24 | function SimditorMarkdown() {
25 | return SimditorMarkdown.__super__.constructor.apply(this, arguments);
26 | }
27 |
28 | SimditorMarkdown.prototype.name = 'markdown';
29 |
30 | SimditorMarkdown.prototype.icon = 'markdown';
31 |
32 | SimditorMarkdown.prototype.needFocus = false;
33 |
34 | SimditorMarkdown.prototype._init = function() {
35 | SimditorMarkdown.__super__._init.call(this);
36 | this.markdownEl = $('').insertBefore(this.editor.body);
37 | this.textarea = $('').attr('placeholder', this.editor.opts.placeholder).appendTo(this.markdownEl);
38 | this.textarea.on('focus', (function(_this) {
39 | return function(e) {
40 | return _this.editor.el.addClass('focus');
41 | };
42 | })(this)).on('blur', (function(_this) {
43 | return function(e) {
44 | return _this.editor.el.removeClass('focus');
45 | };
46 | })(this));
47 | this.editor.on('valuechanged', (function(_this) {
48 | return function(e) {
49 | if (!_this.editor.markdownMode) {
50 | return;
51 | }
52 | return _this._initMarkdownValue();
53 | };
54 | })(this));
55 | this.markdownChange = this.editor.util.throttle((function(_this) {
56 | return function() {
57 | _this._autosizeTextarea();
58 | return _this._convert();
59 | };
60 | })(this), 200);
61 | if (this.editor.util.support.oninput) {
62 | this.textarea.on('input', (function(_this) {
63 | return function(e) {
64 | return _this.markdownChange();
65 | };
66 | })(this));
67 | } else {
68 | this.textarea.on('keyup', (function(_this) {
69 | return function(e) {
70 | return _this.markdownChange();
71 | };
72 | })(this));
73 | }
74 | if (this.editor.opts.markdown) {
75 | return this.editor.on('initialized', (function(_this) {
76 | return function() {
77 | return _this.el.mousedown();
78 | };
79 | })(this));
80 | }
81 | };
82 |
83 | SimditorMarkdown.prototype.status = function() {};
84 |
85 | SimditorMarkdown.prototype.command = function() {
86 | var button, i, len, ref;
87 | this.editor.blur();
88 | this.editor.el.toggleClass('simditor-markdown');
89 | this.editor.markdownMode = this.editor.el.hasClass('simditor-markdown');
90 | if (this.editor.markdownMode) {
91 | this.editor.inputManager.lastCaretPosition = null;
92 | this.editor.hidePopover();
93 | this.editor.body.removeAttr('contenteditable');
94 | this._initMarkdownValue();
95 | } else {
96 | this.textarea.val('');
97 | this.editor.body.attr('contenteditable', 'true');
98 | }
99 | ref = this.editor.toolbar.buttons;
100 | for (i = 0, len = ref.length; i < len; i++) {
101 | button = ref[i];
102 | if (button.name === 'markdown') {
103 | button.setActive(this.editor.markdownMode);
104 | } else {
105 | button.setDisabled(this.editor.markdownMode);
106 | }
107 | }
108 | return null;
109 | };
110 |
111 | SimditorMarkdown.prototype._initMarkdownValue = function() {
112 | this._fileterUnsupportedTags();
113 | this.textarea.val(toMarkdown(this.editor.getValue(), {
114 | gfm: true
115 | }));
116 | return this._autosizeTextarea();
117 | };
118 |
119 | SimditorMarkdown.prototype._autosizeTextarea = function() {
120 | this._textareaPadding || (this._textareaPadding = this.textarea.innerHeight() - this.textarea.height());
121 | return this.textarea.height(this.textarea[0].scrollHeight - this._textareaPadding);
122 | };
123 |
124 | SimditorMarkdown.prototype._convert = function() {
125 | var markdownText, text;
126 | text = this.textarea.val();
127 | markdownText = marked(text);
128 | this.editor.textarea.val(markdownText);
129 | this.editor.body.html(markdownText);
130 | this.editor.formatter.format();
131 | return this.editor.formatter.decorate();
132 | };
133 |
134 | SimditorMarkdown.prototype._fileterUnsupportedTags = function() {
135 | return this.editor.body.find('colgroup').remove();
136 | };
137 |
138 | return SimditorMarkdown;
139 |
140 | })(Simditor.Button);
141 |
142 | Simditor.Toolbar.addButton(SimditorMarkdown);
143 |
144 | return SimditorMarkdown;
145 |
146 | }));
147 |
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/simditor-markdown.min.js:
--------------------------------------------------------------------------------
1 | (function(root,factory){if(typeof define==="function"&&define.amd){define("simditor-markdown",["jquery","simditor","to-markdown","marked"],function(a0,b1,c2,d3){return(root["SimditorMarkdown"]=factory(a0,b1,c2,d3))})}else{if(typeof exports==="object"){module.exports=factory(require("jquery"),require("simditor"),require("to-markdown"),require("marked"))}else{root["SimditorMarkdown"]=factory(jQuery,Simditor,toMarkdown,marked)}}}(this,function($,Simditor,toMarkdown,marked){var SimditorMarkdown,extend=function(child,parent){for(var key in parent){if(hasProp.call(parent,key)){child[key]=parent[key]}}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor();child.__super__=parent.prototype;return child},hasProp={}.hasOwnProperty;SimditorMarkdown=(function(superClass){extend(SimditorMarkdown,superClass);function SimditorMarkdown(){return SimditorMarkdown.__super__.constructor.apply(this,arguments)}SimditorMarkdown.prototype.name="markdown";SimditorMarkdown.prototype.icon="markdown";SimditorMarkdown.prototype.needFocus=false;SimditorMarkdown.prototype._init=function(){SimditorMarkdown.__super__._init.call(this);this.markdownEl=$('').insertBefore(this.editor.body);this.textarea=$("").attr("placeholder",this.editor.opts.placeholder).appendTo(this.markdownEl);this.textarea.on("focus",(function(_this){return function(e){return _this.editor.el.addClass("focus")}})(this)).on("blur",(function(_this){return function(e){return _this.editor.el.removeClass("focus")}})(this));this.editor.on("valuechanged",(function(_this){return function(e){if(!_this.editor.markdownMode){return}return _this._initMarkdownValue()}})(this));this.markdownChange=this.editor.util.throttle((function(_this){return function(){_this._autosizeTextarea();return _this._convert()}})(this),200);if(this.editor.util.support.oninput){this.textarea.on("input",(function(_this){return function(e){return _this.markdownChange()}})(this))}else{this.textarea.on("keyup",(function(_this){return function(e){return _this.markdownChange()}})(this))}if(this.editor.opts.markdown){return this.editor.on("initialized",(function(_this){return function(){return _this.el.mousedown()}})(this))}};SimditorMarkdown.prototype.status=function(){};SimditorMarkdown.prototype.command=function(){var button,i,len,ref;this.editor.blur();this.editor.el.toggleClass("simditor-markdown");this.editor.markdownMode=this.editor.el.hasClass("simditor-markdown");if(this.editor.markdownMode){this.editor.inputManager.lastCaretPosition=null;this.editor.hidePopover();this.editor.body.removeAttr("contenteditable");this._initMarkdownValue()}else{this.textarea.val("");this.editor.body.attr("contenteditable","true")}ref=this.editor.toolbar.buttons;for(i=0,len=ref.length;i-1};return Dropzone})(SimpleModule);Simditor.connect(Dropzone);return Simditor}));(function(root,factory){if(typeof define==="function"&&define.amd){define("simditor-fullscreen",["jquery","simditor"],function(a0,b1){return(root["SimditorFullscreen"]=factory(a0,b1))})}else{if(typeof exports==="object"){module.exports=factory(require("jquery"),require("simditor"))}else{root["SimditorFullscreen"]=factory(jQuery,Simditor)}}}(this,function($,Simditor){var SimditorFullscreen,extend=function(child,parent){for(var key in parent){if(hasProp.call(parent,key)){child[key]=parent[key]}}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor();child.__super__=parent.prototype;return child},hasProp={}.hasOwnProperty;SimditorFullscreen=(function(superClass){extend(SimditorFullscreen,superClass);function SimditorFullscreen(){return SimditorFullscreen.__super__.constructor.apply(this,arguments)}SimditorFullscreen.cls="simditor-fullscreen";SimditorFullscreen.i18n={"zh-CN":{fullscreen:"全屏"}};SimditorFullscreen.prototype.name="fullscreen";SimditorFullscreen.prototype.needFocus=false;SimditorFullscreen.prototype.iconClassOf=function(){return"icon-fullscreen"};SimditorFullscreen.prototype._init=function(){SimditorFullscreen.__super__._init.call(this);this.window=$(window);this.body=$("body");this.editable=this.editor.body;return this.toolbar=this.editor.toolbar.wrapper};SimditorFullscreen.prototype.status=function(){return this.setActive(this.body.hasClass(this.constructor.cls))};SimditorFullscreen.prototype.command=function(){var editablePadding,isFullscreen;this.body.toggleClass(this.constructor.cls);isFullscreen=this.body.hasClass(this.constructor.cls);if(isFullscreen){editablePadding=this.editable.outerHeight()-this.editable.height();this.window.on("resize.simditor-fullscreen-"+this.editor.id,(function(_this){return function(){return _this._resize({height:_this.window.height()-_this.toolbar.outerHeight()-editablePadding})}})(this)).resize()}else{this.window.off("resize.simditor-fullscreen-"+this.editor.id).resize();this._resize({height:"auto"})}return this.setActive(isFullscreen)};SimditorFullscreen.prototype._resize=function(size){return this.editable.height(size.height)};return SimditorFullscreen})(Simditor.Button);Simditor.Toolbar.addButton(SimditorFullscreen);return SimditorFullscreen}));(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else{if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else{if(typeof global!=="undefined"){g=global}else{if(typeof self!=="undefined"){g=self}else{g=this}}}g.toMarkdown=f()}}})(function(){var define,module,exports;return(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a){return a(o,!0)}if(i){return i(o,!0)}var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o0){elem=inqueue.shift();outqueue.push(elem);children=elem.childNodes;for(i=0;i<",">"+content+"<")}function canConvert(node,filter){if(typeof filter==="string"){return filter===node.nodeName.toLowerCase()}if(Array.isArray(filter)){return filter.indexOf(node.nodeName.toLowerCase())!==-1}else{if(typeof filter==="function"){return filter.call(toMarkdown,node)}else{throw new TypeError("`filter` needs to be a string, array, or function")}}}function isFlankedByWhitespace(side,node){var sibling;var regExp;var isFlanked;if(side==="left"){sibling=node.previousSibling;regExp=/ $/}else{sibling=node.nextSibling;regExp=/^ /}if(sibling){if(sibling.nodeType===3){isFlanked=regExp.test(sibling.nodeValue)}else{if(sibling.nodeType===1&&!isBlock(sibling)){isFlanked=regExp.test(sibling.textContent)}}}return isFlanked}function flankingWhitespace(node,content){var leading="";var trailing="";if(!isBlock(node)){var hasLeading=/^[ \r\n\t]/.test(content);var hasTrailing=/[ \r\n\t]$/.test(content);if(hasLeading&&!isFlankedByWhitespace("left",node)){leading=" "}if(hasTrailing&&!isFlankedByWhitespace("right",node)){trailing=" "}}return{leading:leading,trailing:trailing}}function process(node){var replacement;var content=getContent(node);if(!isVoid(node)&&!/A|TH|TD/.test(node.nodeName)&&/^\s*$/i.test(content)){node._replacement="";return}for(var i=0;i=0;i--){process(nodes[i])}output=getContent(clone);return output.replace(/^[\t\r\n]+|[\t\r\n\s]+$/g,"").replace(/\n\s+\n/g,"\n\n").replace(/\n{3,}/g,"\n\n")};toMarkdown.isBlock=isBlock;toMarkdown.isVoid=isVoid;toMarkdown.outer=outer;module.exports=toMarkdown},{"./lib/gfm-converters":2,"./lib/html-parser":3,"./lib/md-converters":4,"collapse-whitespace":7}],2:[function(require,module,exports){function cell(content,node){var index=Array.prototype.indexOf.call(node.parentNode.childNodes,node);
2 | var prefix=" ";if(index===0){prefix="| "}return prefix+content+" |"}var highlightRegEx=/highlight highlight-(\S+)/;module.exports=[{filter:"br",replacement:function(){return"\n"}},{filter:["del","s","strike"],replacement:function(content){return"~~"+content+"~~"}},{filter:function(node){return node.type==="checkbox"&&node.parentNode.nodeName==="LI"},replacement:function(content,node){return(node.checked?"[x]":"[ ]")+" "}},{filter:["th","td"],replacement:function(content,node){return cell(content,node)}},{filter:"tr",replacement:function(content,node){var borderCells="";var alignMap={left:":--",right:"--:",center:":-:"};if(node.parentNode.nodeName==="THEAD"){for(var i=0;i ");return"\n\n"+content+"\n\n"}},{filter:"li",replacement:function(content,node){content=content.replace(/^\s+/,"").replace(/\n/gm,"\n ");var prefix="* ";var parent=node.parentNode;var index=Array.prototype.indexOf.call(parent.children,node)+1;prefix=/ol/i.test(parent.nodeName)?index+". ":"* ";return prefix+content}},{filter:["ul","ol"],replacement:function(content,node){var strings=[];for(var i=0;i').insertBefore(this.editor.body);this.textarea=$("").attr("placeholder",this.editor.opts.placeholder).appendTo(this.markdownEl);this.textarea.on("focus",(function(_this){return function(e){return _this.editor.el.addClass("focus")}})(this)).on("blur",(function(_this){return function(e){return _this.editor.el.removeClass("focus")}})(this));this.editor.on("valuechanged",(function(_this){return function(e){if(!_this.editor.markdownMode){return}return _this._initMarkdownValue()}})(this));this.markdownChange=this.editor.util.throttle((function(_this){return function(){_this._autosizeTextarea();return _this._convert()}})(this),200);if(this.editor.util.support.oninput){this.textarea.on("input",(function(_this){return function(e){return _this.markdownChange()}})(this))}else{this.textarea.on("keyup",(function(_this){return function(e){return _this.markdownChange()}})(this))}if(this.editor.opts.markdown){return this.editor.on("initialized",(function(_this){return function(){return _this.el.mousedown()}})(this))}};SimditorMarkdown.prototype.status=function(){};SimditorMarkdown.prototype.command=function(){var button,i,len,ref;this.editor.blur();this.editor.el.toggleClass("simditor-markdown");this.editor.markdownMode=this.editor.el.hasClass("simditor-markdown");if(this.editor.markdownMode){this.editor.inputManager.lastCaretPosition=null;this.editor.hidePopover();this.editor.body.removeAttr("contenteditable");this._initMarkdownValue()}else{this.textarea.val("");this.editor.body.attr("contenteditable","true")}ref=this.editor.toolbar.buttons;for(i=0,len=ref.length;i 0) {
62 | elem = inqueue.shift()
63 | outqueue.push(elem)
64 | children = elem.childNodes
65 | for (i = 0; i < children.length; i++) {
66 | if (children[i].nodeType === 1) inqueue.push(children[i])
67 | }
68 | }
69 | outqueue.shift()
70 | return outqueue
71 | }
72 |
73 | /*
74 | * Contructs a Markdown string of replacement text for a given node
75 | */
76 |
77 | function getContent (node) {
78 | var text = ''
79 | for (var i = 0; i < node.childNodes.length; i++) {
80 | if (node.childNodes[i].nodeType === 1) {
81 | text += node.childNodes[i]._replacement
82 | } else if (node.childNodes[i].nodeType === 3) {
83 | text += node.childNodes[i].data
84 | } else continue
85 | }
86 | return text
87 | }
88 |
89 | /*
90 | * Returns the HTML string of an element with its contents converted
91 | */
92 |
93 | function outer (node, content) {
94 | return node.cloneNode(false).outerHTML.replace('><', '>' + content + '<')
95 | }
96 |
97 | function canConvert (node, filter) {
98 | if (typeof filter === 'string') {
99 | return filter === node.nodeName.toLowerCase()
100 | }
101 | if (Array.isArray(filter)) {
102 | return filter.indexOf(node.nodeName.toLowerCase()) !== -1
103 | } else if (typeof filter === 'function') {
104 | return filter.call(toMarkdown, node)
105 | } else {
106 | throw new TypeError('`filter` needs to be a string, array, or function')
107 | }
108 | }
109 |
110 | function isFlankedByWhitespace (side, node) {
111 | var sibling
112 | var regExp
113 | var isFlanked
114 |
115 | if (side === 'left') {
116 | sibling = node.previousSibling
117 | regExp = / $/
118 | } else {
119 | sibling = node.nextSibling
120 | regExp = /^ /
121 | }
122 |
123 | if (sibling) {
124 | if (sibling.nodeType === 3) {
125 | isFlanked = regExp.test(sibling.nodeValue)
126 | } else if (sibling.nodeType === 1 && !isBlock(sibling)) {
127 | isFlanked = regExp.test(sibling.textContent)
128 | }
129 | }
130 | return isFlanked
131 | }
132 |
133 | function flankingWhitespace (node, content) {
134 | var leading = ''
135 | var trailing = ''
136 |
137 | if (!isBlock(node)) {
138 | var hasLeading = /^[ \r\n\t]/.test(content)
139 | var hasTrailing = /[ \r\n\t]$/.test(content)
140 |
141 | if (hasLeading && !isFlankedByWhitespace('left', node)) {
142 | leading = ' '
143 | }
144 | if (hasTrailing && !isFlankedByWhitespace('right', node)) {
145 | trailing = ' '
146 | }
147 | }
148 |
149 | return { leading: leading, trailing: trailing }
150 | }
151 |
152 | /*
153 | * Finds a Markdown converter, gets the replacement, and sets it on
154 | * `_replacement`
155 | */
156 |
157 | function process (node) {
158 | var replacement
159 | var content = getContent(node)
160 |
161 | // Remove blank nodes
162 | if (!isVoid(node) && !/A|TH|TD/.test(node.nodeName) && /^\s*$/i.test(content)) {
163 | node._replacement = ''
164 | return
165 | }
166 |
167 | for (var i = 0; i < converters.length; i++) {
168 | var converter = converters[i]
169 |
170 | if (canConvert(node, converter.filter)) {
171 | if (typeof converter.replacement !== 'function') {
172 | throw new TypeError(
173 | '`replacement` needs to be a function that returns a string'
174 | )
175 | }
176 |
177 | var whitespace = flankingWhitespace(node, content)
178 |
179 | if (whitespace.leading || whitespace.trailing) {
180 | content = content.trim()
181 | }
182 | replacement = whitespace.leading +
183 | converter.replacement.call(toMarkdown, content, node) +
184 | whitespace.trailing
185 | break
186 | }
187 | }
188 |
189 | node._replacement = replacement
190 | }
191 |
192 | toMarkdown = function (input, options) {
193 | options = options || {}
194 |
195 | if (typeof input !== 'string') {
196 | throw new TypeError(input + ' is not a string')
197 | }
198 |
199 | if (input === '') {
200 | return ''
201 | }
202 |
203 | // Escape potential ol triggers
204 | input = input.replace(/(\d+)\. /g, '$1\\. ')
205 |
206 | var clone = htmlToDom(input).body
207 | var nodes = bfsOrder(clone)
208 | var output
209 |
210 | converters = mdConverters.slice(0)
211 | if (options.gfm) {
212 | converters = gfmConverters.concat(converters)
213 | }
214 |
215 | if (options.converters) {
216 | converters = options.converters.concat(converters)
217 | }
218 |
219 | // Process through nodes in reverse (so deepest child elements are first).
220 | for (var i = nodes.length - 1; i >= 0; i--) {
221 | process(nodes[i])
222 | }
223 | output = getContent(clone)
224 |
225 | return output.replace(/^[\t\r\n]+|[\t\r\n\s]+$/g, '')
226 | .replace(/\n\s+\n/g, '\n\n')
227 | .replace(/\n{3,}/g, '\n\n')
228 | }
229 |
230 | toMarkdown.isBlock = isBlock
231 | toMarkdown.isVoid = isVoid
232 | toMarkdown.outer = outer
233 |
234 | module.exports = toMarkdown
235 |
236 | },{"./lib/gfm-converters":2,"./lib/html-parser":3,"./lib/md-converters":4,"collapse-whitespace":7}],2:[function(require,module,exports){
237 | 'use strict'
238 |
239 | function cell (content, node) {
240 | var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node)
241 | var prefix = ' '
242 | if (index === 0) prefix = '| '
243 | return prefix + content + ' |'
244 | }
245 |
246 | var highlightRegEx = /highlight highlight-(\S+)/
247 |
248 | module.exports = [
249 | {
250 | filter: 'br',
251 | replacement: function () {
252 | return '\n'
253 | }
254 | },
255 | {
256 | filter: ['del', 's', 'strike'],
257 | replacement: function (content) {
258 | return '~~' + content + '~~'
259 | }
260 | },
261 |
262 | {
263 | filter: function (node) {
264 | return node.type === 'checkbox' && node.parentNode.nodeName === 'LI'
265 | },
266 | replacement: function (content, node) {
267 | return (node.checked ? '[x]' : '[ ]') + ' '
268 | }
269 | },
270 |
271 | {
272 | filter: ['th', 'td'],
273 | replacement: function (content, node) {
274 | return cell(content, node)
275 | }
276 | },
277 |
278 | {
279 | filter: 'tr',
280 | replacement: function (content, node) {
281 | var borderCells = ''
282 | var alignMap = { left: ':--', right: '--:', center: ':-:' }
283 |
284 | if (node.parentNode.nodeName === 'THEAD') {
285 | for (var i = 0; i < node.childNodes.length; i++) {
286 | var align = node.childNodes[i].attributes.align
287 | var border = '---'
288 |
289 | if (align) border = alignMap[align.value] || border
290 |
291 | borderCells += cell(border, node.childNodes[i])
292 | }
293 | }
294 | return '\n' + content + (borderCells ? '\n' + borderCells : '')
295 | }
296 | },
297 |
298 | {
299 | filter: 'table',
300 | replacement: function (content) {
301 | return '\n\n' + content + '\n\n'
302 | }
303 | },
304 |
305 | {
306 | filter: ['thead', 'tbody', 'tfoot'],
307 | replacement: function (content) {
308 | return content
309 | }
310 | },
311 |
312 | // Fenced code blocks
313 | {
314 | filter: function (node) {
315 | return node.nodeName === 'PRE' &&
316 | node.firstChild &&
317 | node.firstChild.nodeName === 'CODE'
318 | },
319 | replacement: function (content, node) {
320 | return '\n\n```\n' + node.firstChild.textContent + '\n```\n\n'
321 | }
322 | },
323 |
324 | // Syntax-highlighted code blocks
325 | {
326 | filter: function (node) {
327 | return node.nodeName === 'PRE' &&
328 | node.parentNode.nodeName === 'DIV' &&
329 | highlightRegEx.test(node.parentNode.className)
330 | },
331 | replacement: function (content, node) {
332 | var language = node.parentNode.className.match(highlightRegEx)[1]
333 | return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n'
334 | }
335 | },
336 |
337 | {
338 | filter: function (node) {
339 | return node.nodeName === 'DIV' &&
340 | highlightRegEx.test(node.className)
341 | },
342 | replacement: function (content) {
343 | return '\n\n' + content + '\n\n'
344 | }
345 | }
346 | ]
347 |
348 | },{}],3:[function(require,module,exports){
349 | /*
350 | * Set up window for Node.js
351 | */
352 |
353 | var _window = (typeof window !== 'undefined' ? window : this)
354 |
355 | /*
356 | * Parsing HTML strings
357 | */
358 |
359 | function canParseHtmlNatively () {
360 | var Parser = _window.DOMParser
361 | var canParse = false
362 |
363 | // Adapted from https://gist.github.com/1129031
364 | // Firefox/Opera/IE throw errors on unsupported types
365 | try {
366 | // WebKit returns null on unsupported types
367 | if (new Parser().parseFromString('', 'text/html')) {
368 | canParse = true
369 | }
370 | } catch (e) {}
371 |
372 | return canParse
373 | }
374 |
375 | function createHtmlParser () {
376 | var Parser = function () {}
377 |
378 | // For Node.js environments
379 | if (typeof document === 'undefined') {
380 | var jsdom = require('jsdom')
381 | Parser.prototype.parseFromString = function (string) {
382 | return jsdom.jsdom(string, {
383 | features: {
384 | FetchExternalResources: [],
385 | ProcessExternalResources: false
386 | }
387 | })
388 | }
389 | } else {
390 | if (!shouldUseActiveX()) {
391 | Parser.prototype.parseFromString = function (string) {
392 | var doc = document.implementation.createHTMLDocument('')
393 | doc.open()
394 | doc.write(string)
395 | doc.close()
396 | return doc
397 | }
398 | } else {
399 | Parser.prototype.parseFromString = function (string) {
400 | var doc = new window.ActiveXObject('htmlfile')
401 | doc.designMode = 'on' // disable on-page scripts
402 | doc.open()
403 | doc.write(string)
404 | doc.close()
405 | return doc
406 | }
407 | }
408 | }
409 | return Parser
410 | }
411 |
412 | function shouldUseActiveX () {
413 | var useActiveX = false
414 |
415 | try {
416 | document.implementation.createHTMLDocument('').open()
417 | } catch (e) {
418 | if (window.ActiveXObject) useActiveX = true
419 | }
420 |
421 | return useActiveX
422 | }
423 |
424 | module.exports = canParseHtmlNatively() ? _window.DOMParser : createHtmlParser()
425 |
426 | },{"jsdom":6}],4:[function(require,module,exports){
427 | 'use strict'
428 |
429 | module.exports = [
430 | {
431 | filter: 'p',
432 | replacement: function (content) {
433 | return '\n\n' + content + '\n\n'
434 | }
435 | },
436 |
437 | {
438 | filter: 'br',
439 | replacement: function () {
440 | return ' \n'
441 | }
442 | },
443 |
444 | {
445 | filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
446 | replacement: function (content, node) {
447 | var hLevel = node.nodeName.charAt(1)
448 | var hPrefix = ''
449 | for (var i = 0; i < hLevel; i++) {
450 | hPrefix += '#'
451 | }
452 | return '\n\n' + hPrefix + ' ' + content + '\n\n'
453 | }
454 | },
455 |
456 | {
457 | filter: 'hr',
458 | replacement: function () {
459 | return '\n\n* * *\n\n'
460 | }
461 | },
462 |
463 | {
464 | filter: ['em', 'i'],
465 | replacement: function (content) {
466 | return '_' + content + '_'
467 | }
468 | },
469 |
470 | {
471 | filter: ['strong', 'b'],
472 | replacement: function (content) {
473 | return '**' + content + '**'
474 | }
475 | },
476 |
477 | // Inline code
478 | {
479 | filter: function (node) {
480 | var hasSiblings = node.previousSibling || node.nextSibling
481 | var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings
482 |
483 | return node.nodeName === 'CODE' && !isCodeBlock
484 | },
485 | replacement: function (content) {
486 | return '`' + content + '`'
487 | }
488 | },
489 |
490 | {
491 | filter: function (node) {
492 | return node.nodeName === 'A' && node.getAttribute('href')
493 | },
494 | replacement: function (content, node) {
495 | var titlePart = node.title ? ' "' + node.title + '"' : ''
496 | return '[' + content + '](' + node.getAttribute('href') + titlePart + ')'
497 | }
498 | },
499 |
500 | {
501 | filter: 'img',
502 | replacement: function (content, node) {
503 | var alt = node.alt || ''
504 | var src = node.getAttribute('src') || ''
505 | var title = node.title || ''
506 | var titlePart = title ? ' "' + title + '"' : ''
507 | return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
508 | }
509 | },
510 |
511 | // Code blocks
512 | {
513 | filter: function (node) {
514 | return node.nodeName === 'PRE' && node.firstChild.nodeName === 'CODE'
515 | },
516 | replacement: function (content, node) {
517 | return '\n\n ' + node.firstChild.textContent.replace(/\n/g, '\n ') + '\n\n'
518 | }
519 | },
520 |
521 | {
522 | filter: 'blockquote',
523 | replacement: function (content) {
524 | content = content.trim()
525 | content = content.replace(/\n{3,}/g, '\n\n')
526 | content = content.replace(/^/gm, '> ')
527 | return '\n\n' + content + '\n\n'
528 | }
529 | },
530 |
531 | {
532 | filter: 'li',
533 | replacement: function (content, node) {
534 | content = content.replace(/^\s+/, '').replace(/\n/gm, '\n ')
535 | var prefix = '* '
536 | var parent = node.parentNode
537 | var index = Array.prototype.indexOf.call(parent.children, node) + 1
538 |
539 | prefix = /ol/i.test(parent.nodeName) ? index + '. ' : '* '
540 | return prefix + content
541 | }
542 | },
543 |
544 | {
545 | filter: ['ul', 'ol'],
546 | replacement: function (content, node) {
547 | var strings = []
548 | for (var i = 0; i < node.childNodes.length; i++) {
549 | strings.push(node.childNodes[i]._replacement)
550 | }
551 |
552 | if (/li/i.test(node.parentNode.nodeName)) {
553 | return '\n' + strings.join('\n')
554 | }
555 | return '\n\n' + strings.join('\n') + '\n\n'
556 | }
557 | },
558 |
559 | {
560 | filter: function (node) {
561 | return this.isBlock(node)
562 | },
563 | replacement: function (content, node) {
564 | return '\n\n' + this.outer(node, content) + '\n\n'
565 | }
566 | },
567 |
568 | // Anything else!
569 | {
570 | filter: function () {
571 | return true
572 | },
573 | replacement: function (content, node) {
574 | return this.outer(node, content)
575 | }
576 | }
577 | ]
578 |
579 | },{}],5:[function(require,module,exports){
580 | /**
581 | * This file automatically generated from `build.js`.
582 | * Do not manually edit.
583 | */
584 |
585 | module.exports = [
586 | "address",
587 | "article",
588 | "aside",
589 | "audio",
590 | "blockquote",
591 | "canvas",
592 | "dd",
593 | "div",
594 | "dl",
595 | "fieldset",
596 | "figcaption",
597 | "figure",
598 | "footer",
599 | "form",
600 | "h1",
601 | "h2",
602 | "h3",
603 | "h4",
604 | "h5",
605 | "h6",
606 | "header",
607 | "hgroup",
608 | "hr",
609 | "main",
610 | "nav",
611 | "noscript",
612 | "ol",
613 | "output",
614 | "p",
615 | "pre",
616 | "section",
617 | "table",
618 | "tfoot",
619 | "ul",
620 | "video"
621 | ];
622 |
623 | },{}],6:[function(require,module,exports){
624 |
625 | },{}],7:[function(require,module,exports){
626 | 'use strict';
627 |
628 | var voidElements = require('void-elements');
629 | Object.keys(voidElements).forEach(function (name) {
630 | voidElements[name.toUpperCase()] = 1;
631 | });
632 |
633 | var blockElements = {};
634 | require('block-elements').forEach(function (name) {
635 | blockElements[name.toUpperCase()] = 1;
636 | });
637 |
638 | /**
639 | * isBlockElem(node) determines if the given node is a block element.
640 | *
641 | * @param {Node} node
642 | * @return {Boolean}
643 | */
644 | function isBlockElem(node) {
645 | return !!(node && blockElements[node.nodeName]);
646 | }
647 |
648 | /**
649 | * isVoid(node) determines if the given node is a void element.
650 | *
651 | * @param {Node} node
652 | * @return {Boolean}
653 | */
654 | function isVoid(node) {
655 | return !!(node && voidElements[node.nodeName]);
656 | }
657 |
658 | /**
659 | * whitespace(elem [, isBlock]) removes extraneous whitespace from an
660 | * the given element. The function isBlock may optionally be passed in
661 | * to determine whether or not an element is a block element; if none
662 | * is provided, defaults to using the list of block elements provided
663 | * by the `block-elements` module.
664 | *
665 | * @param {Node} elem
666 | * @param {Function} blockTest
667 | */
668 | function collapseWhitespace(elem, isBlock) {
669 | if (!elem.firstChild || elem.nodeName === 'PRE') return;
670 |
671 | if (typeof isBlock !== 'function') {
672 | isBlock = isBlockElem;
673 | }
674 |
675 | var prevText = null;
676 | var prevVoid = false;
677 |
678 | var prev = null;
679 | var node = next(prev, elem);
680 |
681 | while (node !== elem) {
682 | if (node.nodeType === 3) {
683 | // Node.TEXT_NODE
684 | var text = node.data.replace(/[ \r\n\t]+/g, ' ');
685 |
686 | if ((!prevText || / $/.test(prevText.data)) && !prevVoid && text[0] === ' ') {
687 | text = text.substr(1);
688 | }
689 |
690 | // `text` might be empty at this point.
691 | if (!text) {
692 | node = remove(node);
693 | continue;
694 | }
695 |
696 | node.data = text;
697 | prevText = node;
698 | } else if (node.nodeType === 1) {
699 | // Node.ELEMENT_NODE
700 | if (isBlock(node) || node.nodeName === 'BR') {
701 | if (prevText) {
702 | prevText.data = prevText.data.replace(/ $/, '');
703 | }
704 |
705 | prevText = null;
706 | prevVoid = false;
707 | } else if (isVoid(node)) {
708 | // Avoid trimming space around non-block, non-BR void elements.
709 | prevText = null;
710 | prevVoid = true;
711 | }
712 | } else {
713 | node = remove(node);
714 | continue;
715 | }
716 |
717 | var nextNode = next(prev, node);
718 | prev = node;
719 | node = nextNode;
720 | }
721 |
722 | if (prevText) {
723 | prevText.data = prevText.data.replace(/ $/, '');
724 | if (!prevText.data) {
725 | remove(prevText);
726 | }
727 | }
728 | }
729 |
730 | /**
731 | * remove(node) removes the given node from the DOM and returns the
732 | * next node in the sequence.
733 | *
734 | * @param {Node} node
735 | * @return {Node} node
736 | */
737 | function remove(node) {
738 | var next = node.nextSibling || node.parentNode;
739 |
740 | node.parentNode.removeChild(node);
741 |
742 | return next;
743 | }
744 |
745 | /**
746 | * next(prev, current) returns the next node in the sequence, given the
747 | * current and previous nodes.
748 | *
749 | * @param {Node} prev
750 | * @param {Node} current
751 | * @return {Node}
752 | */
753 | function next(prev, current) {
754 | if (prev && prev.parentNode === current || current.nodeName === 'PRE') {
755 | return current.nextSibling || current.parentNode;
756 | }
757 |
758 | return current.firstChild || current.nextSibling || current.parentNode;
759 | }
760 |
761 | module.exports = collapseWhitespace;
762 |
763 | },{"block-elements":5,"void-elements":8}],8:[function(require,module,exports){
764 | /**
765 | * This file automatically generated from `pre-publish.js`.
766 | * Do not manually edit.
767 | */
768 |
769 | module.exports = {
770 | "area": true,
771 | "base": true,
772 | "br": true,
773 | "col": true,
774 | "embed": true,
775 | "hr": true,
776 | "img": true,
777 | "input": true,
778 | "keygen": true,
779 | "link": true,
780 | "menuitem": true,
781 | "meta": true,
782 | "param": true,
783 | "source": true,
784 | "track": true,
785 | "wbr": true
786 | };
787 |
788 | },{}]},{},[1])(1)
789 | });
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/to-markdown.min.js:
--------------------------------------------------------------------------------
1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else{if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else{if(typeof global!=="undefined"){g=global}else{if(typeof self!=="undefined"){g=self}else{g=this}}}g.toMarkdown=f()}}})(function(){var define,module,exports;return(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a){return a(o,!0)}if(i){return i(o,!0)}var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o0){elem=inqueue.shift();outqueue.push(elem);children=elem.childNodes;for(i=0;i<",">"+content+"<")}function canConvert(node,filter){if(typeof filter==="string"){return filter===node.nodeName.toLowerCase()}if(Array.isArray(filter)){return filter.indexOf(node.nodeName.toLowerCase())!==-1}else{if(typeof filter==="function"){return filter.call(toMarkdown,node)}else{throw new TypeError("`filter` needs to be a string, array, or function")}}}function isFlankedByWhitespace(side,node){var sibling;var regExp;var isFlanked;if(side==="left"){sibling=node.previousSibling;regExp=/ $/}else{sibling=node.nextSibling;regExp=/^ /}if(sibling){if(sibling.nodeType===3){isFlanked=regExp.test(sibling.nodeValue)}else{if(sibling.nodeType===1&&!isBlock(sibling)){isFlanked=regExp.test(sibling.textContent)}}}return isFlanked}function flankingWhitespace(node,content){var leading="";var trailing="";if(!isBlock(node)){var hasLeading=/^[ \r\n\t]/.test(content);var hasTrailing=/[ \r\n\t]$/.test(content);if(hasLeading&&!isFlankedByWhitespace("left",node)){leading=" "}if(hasTrailing&&!isFlankedByWhitespace("right",node)){trailing=" "}}return{leading:leading,trailing:trailing}}function process(node){var replacement;var content=getContent(node);if(!isVoid(node)&&!/A|TH|TD/.test(node.nodeName)&&/^\s*$/i.test(content)){node._replacement="";return}for(var i=0;i=0;i--){process(nodes[i])}output=getContent(clone);return output.replace(/^[\t\r\n]+|[\t\r\n\s]+$/g,"").replace(/\n\s+\n/g,"\n\n").replace(/\n{3,}/g,"\n\n")};toMarkdown.isBlock=isBlock;toMarkdown.isVoid=isVoid;toMarkdown.outer=outer;module.exports=toMarkdown},{"./lib/gfm-converters":2,"./lib/html-parser":3,"./lib/md-converters":4,"collapse-whitespace":7}],2:[function(require,module,exports){function cell(content,node){var index=Array.prototype.indexOf.call(node.parentNode.childNodes,node);
2 | var prefix=" ";if(index===0){prefix="| "}return prefix+content+" |"}var highlightRegEx=/highlight highlight-(\S+)/;module.exports=[{filter:"br",replacement:function(){return"\n"}},{filter:["del","s","strike"],replacement:function(content){return"~~"+content+"~~"}},{filter:function(node){return node.type==="checkbox"&&node.parentNode.nodeName==="LI"},replacement:function(content,node){return(node.checked?"[x]":"[ ]")+" "}},{filter:["th","td"],replacement:function(content,node){return cell(content,node)}},{filter:"tr",replacement:function(content,node){var borderCells="";var alignMap={left:":--",right:"--:",center:":-:"};if(node.parentNode.nodeName==="THEAD"){for(var i=0;i ");return"\n\n"+content+"\n\n"}},{filter:"li",replacement:function(content,node){content=content.replace(/^\s+/,"").replace(/\n/gm,"\n ");var prefix="* ";var parent=node.parentNode;var index=Array.prototype.indexOf.call(parent.children,node)+1;prefix=/ol/i.test(parent.nodeName)?index+". ":"* ";return prefix+content}},{filter:["ul","ol"],replacement:function(content,node){var strings=[];for(var i=0;i 0 && _this.files.length < _this.opts.connectionCount) {
46 | return _this.upload(_this.queue.shift());
47 | } else {
48 | return _this.uploading = false;
49 | }
50 | };
51 | })(this));
52 | return $(window).on('beforeunload.uploader-' + this.id, (function(_this) {
53 | return function(e) {
54 | if (!_this.uploading) {
55 | return;
56 | }
57 | e.originalEvent.returnValue = _this._t('leaveConfirm');
58 | return _this._t('leaveConfirm');
59 | };
60 | })(this));
61 | };
62 |
63 | Uploader.prototype.generateId = (function() {
64 | var id;
65 | id = 0;
66 | return function() {
67 | return id += 1;
68 | };
69 | })();
70 |
71 | Uploader.prototype.upload = function(file, opts) {
72 | var f, i, key, len;
73 | if (opts == null) {
74 | opts = {};
75 | }
76 | if (file == null) {
77 | return;
78 | }
79 | if ($.isArray(file) || file instanceof FileList) {
80 | for (i = 0, len = file.length; i < len; i++) {
81 | f = file[i];
82 | this.upload(f, opts);
83 | }
84 | } else if ($(file).is('input:file')) {
85 | key = $(file).attr('name');
86 | if (key) {
87 | opts.fileKey = key;
88 | }
89 | this.upload($.makeArray($(file)[0].files), opts);
90 | } else if (!file.id || !file.obj) {
91 | file = this.getFile(file);
92 | }
93 | if (!(file && file.obj)) {
94 | return;
95 | }
96 | $.extend(file, opts);
97 | if (this.files.length >= this.opts.connectionCount) {
98 | this.queue.push(file);
99 | return;
100 | }
101 | if (this.triggerHandler('beforeupload', [file]) === false) {
102 | return;
103 | }
104 | this.files.push(file);
105 | this._xhrUpload(file);
106 | return this.uploading = true;
107 | };
108 |
109 | Uploader.prototype.getFile = function(fileObj) {
110 | var name, ref, ref1;
111 | if (fileObj instanceof window.File || fileObj instanceof window.Blob) {
112 | name = (ref = fileObj.fileName) != null ? ref : fileObj.name;
113 | } else {
114 | return null;
115 | }
116 | return {
117 | id: this.generateId(),
118 | url: this.opts.url,
119 | params: this.opts.params,
120 | fileKey: this.opts.fileKey,
121 | name: name,
122 | size: (ref1 = fileObj.fileSize) != null ? ref1 : fileObj.size,
123 | ext: name ? name.split('.').pop().toLowerCase() : '',
124 | obj: fileObj
125 | };
126 | };
127 |
128 | Uploader.prototype._xhrUpload = function(file) {
129 | var formData, k, ref, v;
130 | formData = new FormData();
131 | formData.append(file.fileKey, file.obj);
132 | formData.append("original_filename", file.name);
133 | if (file.params) {
134 | ref = file.params;
135 | for (k in ref) {
136 | v = ref[k];
137 | formData.append(k, v);
138 | }
139 | }
140 | return file.xhr = $.ajax({
141 | url: file.url,
142 | data: formData,
143 | processData: false,
144 | contentType: false,
145 | type: 'POST',
146 | headers: {
147 | 'X-File-Name': encodeURIComponent(file.name)
148 | },
149 | xhr: function() {
150 | var req;
151 | req = $.ajaxSettings.xhr();
152 | if (req) {
153 | req.upload.onprogress = (function(_this) {
154 | return function(e) {
155 | return _this.progress(e);
156 | };
157 | })(this);
158 | }
159 | return req;
160 | },
161 | progress: (function(_this) {
162 | return function(e) {
163 | if (!e.lengthComputable) {
164 | return;
165 | }
166 | return _this.trigger('uploadprogress', [file, e.loaded, e.total]);
167 | };
168 | })(this),
169 | error: (function(_this) {
170 | return function(xhr, status, err) {
171 | return _this.trigger('uploaderror', [file, xhr, status]);
172 | };
173 | })(this),
174 | success: (function(_this) {
175 | return function(result) {
176 | _this.trigger('uploadprogress', [file, file.size, file.size]);
177 | _this.trigger('uploadsuccess', [file, result]);
178 | return $(document).trigger('uploadsuccess', [file, result, _this]);
179 | };
180 | })(this),
181 | complete: (function(_this) {
182 | return function(xhr, status) {
183 | return _this.trigger('uploadcomplete', [file, xhr.responseText]);
184 | };
185 | })(this)
186 | });
187 | };
188 |
189 | Uploader.prototype.cancel = function(file) {
190 | var f, i, len, ref;
191 | if (!file.id) {
192 | ref = this.files;
193 | for (i = 0, len = ref.length; i < len; i++) {
194 | f = ref[i];
195 | if (f.id === file * 1) {
196 | file = f;
197 | break;
198 | }
199 | }
200 | }
201 | this.trigger('uploadcancel', [file]);
202 | if (file.xhr) {
203 | file.xhr.abort();
204 | }
205 | return file.xhr = null;
206 | };
207 |
208 | Uploader.prototype.readImageFile = function(fileObj, callback) {
209 | var fileReader, img;
210 | if (!$.isFunction(callback)) {
211 | return;
212 | }
213 | img = new Image();
214 | img.onload = function() {
215 | return callback(img);
216 | };
217 | img.onerror = function() {
218 | return callback();
219 | };
220 | if (window.FileReader && FileReader.prototype.readAsDataURL && /^image/.test(fileObj.type)) {
221 | fileReader = new FileReader();
222 | fileReader.onload = function(e) {
223 | return img.src = e.target.result;
224 | };
225 | return fileReader.readAsDataURL(fileObj);
226 | } else {
227 | return callback();
228 | }
229 | };
230 |
231 | Uploader.prototype.destroy = function() {
232 | var file, i, len, ref;
233 | this.queue.length = 0;
234 | ref = this.files;
235 | for (i = 0, len = ref.length; i < len; i++) {
236 | file = ref[i];
237 | this.cancel(file);
238 | }
239 | $(window).off('.uploader-' + this.id);
240 | return $(document).off('.uploader-' + this.id);
241 | };
242 |
243 | Uploader.i18n = {
244 | 'zh-CN': {
245 | leaveConfirm: '正在上传文件,如果离开上传会自动取消'
246 | }
247 | };
248 |
249 | Uploader.locale = 'zh-CN';
250 |
251 | return Uploader;
252 |
253 | })(SimpleModule);
254 |
255 | uploader = function(opts) {
256 | return new Uploader(opts);
257 | };
258 |
259 | return uploader;
260 |
261 | }));
262 |
--------------------------------------------------------------------------------
/simditor/static/simditor/scripts/uploader.min.js:
--------------------------------------------------------------------------------
1 | !function(a,b){"function"==typeof define&&define.amd?
2 | // AMD. Register as an anonymous module unless amdModuleId is set
3 | define("simple-uploader",["jquery","simple-module"],function(c,d){return a.uploader=b(c,d)}):"object"==typeof exports?
4 | // Node. Does not work with strict CommonJS, but
5 | // only CommonJS-like environments that support module.exports,
6 | // like Node.
7 | module.exports=b(require("jquery"),require("simple-module")):(a.simple=a.simple||{},a.simple.uploader=b(jQuery,SimpleModule))}(this,function(a,b){var c,d,e=function(a,b){function c(){this.constructor=a}for(var d in b)f.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},f={}.hasOwnProperty;return c=function(b){function c(){return c.__super__.constructor.apply(this,arguments)}return e(c,b),c.count=0,c.prototype.opts={url:"",params:null,fileKey:"upload_file",connectionCount:3},c.prototype._init=function(){return this.files=[],this.queue=[],this.id=++c.count,this.on("uploadcomplete",function(b){return function(c,d){return b.files.splice(a.inArray(d,b.files),1),b.queue.length>0&&b.files.lengthe;e++)d=b[e],this.upload(d,c);else a(b).is("input:file")?(f=a(b).attr("name"),f&&(c.fileKey=f),this.upload(a.makeArray(a(b)[0].files),c)):b.id&&b.obj||(b=this.getFile(b));if(b&&b.obj){if(a.extend(b,c),this.files.length>=this.opts.connectionCount)return void this.queue.push(b);if(this.triggerHandler("beforeupload",[b])!==!1)return this.files.push(b),this._xhrUpload(b),this.uploading=!0}}},c.prototype.getFile=function(a){var b,c,d;return a instanceof window.File||a instanceof window.Blob?(b=null!=(c=a.fileName)?c:a.name,{id:this.generateId(),url:this.opts.url,params:this.opts.params,fileKey:this.opts.fileKey,name:b,size:null!=(d=a.fileSize)?d:a.size,ext:b?b.split(".").pop().toLowerCase():"",obj:a}):null},c.prototype._xhrUpload=function(b){var c,d,e,f;if(c=new FormData,c.append(b.fileKey,b.obj),c.append("original_filename",b.name),b.params){e=b.params;for(d in e)f=e[d],c.append(d,f)}return b.xhr=a.ajax({url:b.url,data:c,processData:!1,contentType:!1,type:"POST",headers:{"X-File-Name":encodeURIComponent(b.name)},xhr:function(){var b;return b=a.ajaxSettings.xhr(),b&&(b.upload.onprogress=function(a){return function(b){return a.progress(b)}}(this)),b},progress:function(a){return function(c){return c.lengthComputable?a.trigger("uploadprogress",[b,c.loaded,c.total]):void 0}}(this),error:function(a){return function(c,d,e){return a.trigger("uploaderror",[b,c,d])}}(this),success:function(c){return function(d){return c.trigger("uploadprogress",[b,b.size,b.size]),c.trigger("uploadsuccess",[b,d]),a(document).trigger("uploadsuccess",[b,d,c])}}(this),complete:function(a){return function(c,d){return a.trigger("uploadcomplete",[b,c.responseText])}}(this)})},c.prototype.cancel=function(a){var b,c,d,e;if(!a.id)for(e=this.files,c=0,d=e.length;d>c;c++)if(b=e[c],b.id===1*a){a=b;break}return this.trigger("uploadcancel",[a]),a.xhr&&a.xhr.abort(),a.xhr=null},c.prototype.readImageFile=function(b,c){var d,e;if(a.isFunction(c))return e=new Image,e.onload=function(){return c(e)},e.onerror=function(){return c()},window.FileReader&&FileReader.prototype.readAsDataURL&&/^image/.test(b.type)?(d=new FileReader,d.onload=function(a){return e.src=a.target.result},d.readAsDataURL(b)):c()},c.prototype.destroy=function(){var b,c,d,e;for(this.queue.length=0,e=this.files,c=0,d=e.length;d>c;c++)b=e[c],this.cancel(b);return a(window).off(".uploader-"+this.id),a(document).off(".uploader-"+this.id)},c.i18n={"zh-CN":{leaveConfirm:"正在上传文件,如果离开上传会自动取消"}},c.locale="zh-CN",c}(b),d=function(a){return new c(a)}});
--------------------------------------------------------------------------------
/simditor/static/simditor/simditor-init.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var djangoJQuery;
3 | if (typeof jQuery == 'undefined' && typeof django == 'undefined') {
4 | console.error('ERROR django-simditor missing jQuery. Set SIMDITOR_JQUERY_URL or provide jQuery in the template.');
5 | } else if (typeof django != 'undefined') {
6 | djangoJQuery = django.jQuery;
7 | }
8 |
9 | var $ = jQuery || djangoJQuery;
10 | $(function() {
11 |
12 | initialiseSimditor();
13 | function initialiseSimditor() {
14 | $('textarea[data-type=simditortype]').each(function() {
15 |
16 | if($(this).data('processed') == "0" && $(this).attr('data-id').indexOf('__prefix__') == -1){
17 | $(this).data('processed', "1");
18 | var dataConfig = $(this).data('config');
19 | new Simditor({
20 | textarea: $(this),
21 | upload: dataConfig.upload,
22 | cleanPaste: dataConfig.cleanPaste,
23 | tabIndent: dataConfig.tabIndent,
24 | pasteImage: dataConfig.pasteImage,
25 | toolbar: dataConfig.toolbar,
26 | emoji: dataConfig.emoji
27 | });
28 | }
29 | });
30 | }
31 |
32 | });
33 |
34 | })();
35 |
--------------------------------------------------------------------------------
/simditor/static/simditor/styles/editor.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | $simditor-button-height: 40px;
4 | $simditor-button-width: 46px;
5 |
6 | .simditor {
7 | position: relative;
8 | border: 1px solid #c9d8db;
9 |
10 | .simditor-wrapper {
11 | position: relative;
12 | background: #ffffff;
13 |
14 | & > textarea {
15 | display: none !important;
16 | width: 100%;
17 | box-sizing: border-box;
18 | font-family: monaco;
19 | font-size: 16px;
20 | line-height: 1.6;
21 | border: none;
22 | padding: 22px 15px 40px;
23 | min-height: 300px;
24 | outline: none;
25 | background: transparent;
26 | resize: none;
27 | }
28 |
29 | .simditor-placeholder {
30 | display: none;
31 | position: absolute;
32 | left: 0;
33 | z-index: 0;
34 | padding: 22px 15px;
35 | font-size: 16px;
36 | font-family: arial, sans-serif;
37 | line-height: 1.5;
38 | color: #999999;
39 | background: transparent;
40 | }
41 |
42 | &.toolbar-floating {
43 | .simditor-toolbar {
44 | position: fixed;
45 | top: 0;
46 | z-index: 10;
47 | box-shadow: 0 0 6px rgba(0,0,0,0.1);
48 | }
49 | }
50 |
51 | .simditor-image-loading {
52 | width: 100%;
53 | height: 100%;
54 | position: absolute;
55 | top: 0;
56 | left: 0;
57 | z-index: 2;
58 |
59 | .progress {
60 | width: 100%;
61 | height: 100%;
62 | background: rgba(0,0,0,0.4);
63 | position: absolute;
64 | bottom: 0;
65 | left: 0;
66 | }
67 | }
68 | }
69 |
70 | .simditor-body {
71 | padding: 22px 15px 40px;
72 | min-height: 300px;
73 | outline: none;
74 | cursor: text;
75 | position: relative;
76 | z-index: 1;
77 | background: transparent;
78 |
79 | a.selected {
80 | background: #b3d4fd;
81 | }
82 |
83 | a.simditor-mention {
84 | cursor: pointer;
85 | }
86 |
87 | .simditor-table {
88 | position: relative;
89 |
90 | &.resizing {
91 | cursor: col-resize;
92 | }
93 |
94 | .simditor-resize-handle {
95 | position: absolute;
96 | left: 0;
97 | top: 0;
98 | width: 10px;
99 | height: 100%;
100 | cursor: col-resize;
101 | }
102 | }
103 |
104 | pre {
105 | /*min-height: 28px;*/
106 | box-sizing: border-box;
107 | -moz-box-sizing: border-box;
108 | word-wrap: break-word!important;
109 | white-space: pre-wrap!important;
110 | }
111 |
112 | img {
113 | cursor: pointer;
114 |
115 | &.selected {
116 | box-shadow: 0 0 0 4px #cccccc;
117 | }
118 | }
119 | }
120 |
121 | .simditor-paste-bin {
122 | position: fixed;
123 | bottom: 10px;
124 | right: 10px;
125 | width: 1px;
126 | height: 20px;
127 | font-size: 1px;
128 | line-height: 1px;
129 | overflow: hidden;
130 | padding: 0;
131 | margin: 0;
132 | opacity: 0;
133 | -webkit-user-select: text;
134 | }
135 |
136 | .simditor-toolbar {
137 | border-bottom: 1px solid #eeeeee;
138 | background: #ffffff;
139 | width: 100%;
140 |
141 | & > ul {
142 | margin: 0;
143 | padding: 0 0 0 6px;
144 | list-style: none;
145 |
146 | & > li {
147 | position: relative;
148 | display: inline-block;
149 | font-size: 0;
150 |
151 | & > span.separator {
152 | display: inline-block;
153 | background: #cfcfcf;
154 | width: 1px;
155 | height: 18px;
156 | margin: ($simditor-button-height - 18px) / 2 15px;
157 | vertical-align: middle;
158 | }
159 |
160 | & > .toolbar-item {
161 | display: inline-block;
162 | width: $simditor-button-width;
163 | height: $simditor-button-height;
164 | outline: none;
165 | color: #333333;
166 | font-size: 15px;
167 | line-height: $simditor-button-height;
168 | vertical-align: middle;
169 | text-align: center;
170 | text-decoration: none;
171 |
172 | span {
173 | opacity: 0.6;
174 |
175 | &.simditor-icon {
176 | display: inline;
177 | line-height: normal;
178 | }
179 | }
180 |
181 | &:hover span {
182 | opacity: 1;
183 | }
184 |
185 | &.active {
186 | background: #eeeeee;
187 |
188 | span {
189 | opacity: 1;
190 | }
191 | }
192 |
193 | &.disabled {
194 | cursor: default;
195 |
196 | span {
197 | opacity: 0.3;
198 | }
199 | }
200 |
201 | &.toolbar-item-title {
202 | span:before {
203 | content: "H";
204 | font-size: 19px;
205 | font-weight: bold;
206 | font-family: 'Times New Roman';
207 | }
208 |
209 | &.active-h1 span:before {
210 | content: 'H1';
211 | font-size: 18px;
212 | }
213 |
214 | &.active-h2 span:before {
215 | content: 'H2';
216 | font-size: 18px;
217 | }
218 |
219 | &.active-h3 span:before {
220 | content: 'H3';
221 | font-size: 18px;
222 | }
223 | }
224 |
225 | &.toolbar-item-image {
226 | position: relative;
227 | overflow: hidden;
228 |
229 | & > input[type=file] {
230 | position: absolute;
231 | right: 0px;
232 | top: 0px;
233 | opacity: 0;
234 | font-size: 100px;
235 | cursor: pointer;
236 | }
237 | }
238 | }
239 |
240 | &.menu-on {
241 | .toolbar-item {
242 | position: relative;
243 | z-index: 20;
244 | background: #ffffff;
245 | box-shadow: 0 1px 4px rgba(0,0,0,0.3);
246 |
247 | span {
248 | opacity: 1;
249 | }
250 | }
251 |
252 | .toolbar-menu {
253 | display: block;
254 | }
255 | }
256 | }
257 | }
258 |
259 | .toolbar-menu {
260 | display: none;
261 | position: absolute;
262 | top: $simditor-button-height;
263 | left: 0;
264 | z-index: 21;
265 | background: #ffffff;
266 | text-align: left;
267 | box-shadow: 0 0 4px rgba(0,0,0,0.3);
268 |
269 | &:before {
270 | content: '';
271 | display: block;
272 | width: $simditor-button-width;
273 | height: 4px;
274 | background: #ffffff;
275 | position: absolute;
276 | top: -3px;
277 | left: 0;
278 | }
279 |
280 | ul {
281 | min-width: 160px;
282 | list-style: none;
283 | margin: 0;
284 | padding: 10px 1px;
285 |
286 | & > li {
287 |
288 | .menu-item {
289 | display: block;
290 | font-size:16px;
291 | line-height: 2em;
292 | padding: 0 10px;
293 | text-decoration: none;
294 | color: #666666;
295 |
296 | &:hover {
297 | background: #f6f6f6;
298 | }
299 |
300 | &.menu-item-h1 {
301 | font-size: 24px;
302 | color: #333333;
303 | }
304 |
305 | &.menu-item-h2 {
306 | font-size: 22px;
307 | color: #333333;
308 | }
309 |
310 | &.menu-item-h3 {
311 | font-size: 20px;
312 | color: #333333;
313 | }
314 |
315 | &.menu-item-h4 {
316 | font-size: 18px;
317 | color: #333333;
318 | }
319 |
320 | &.menu-item-h5 {
321 | font-size: 16px;
322 | color: #333333;
323 | }
324 | }
325 |
326 | .separator {
327 | display: block;
328 | border-top: 1px solid #cccccc;
329 | height: 0;
330 | line-height: 0;
331 | font-size: 0;
332 | margin: 6px 0;
333 | }
334 | }
335 |
336 | }
337 |
338 | &.toolbar-menu-color {
339 | width: 96px;
340 |
341 | .color-list {
342 | height: 40px;
343 | margin: 10px 6px 6px 10px;
344 | padding: 0;
345 |
346 | min-width: 0;
347 |
348 | li {
349 | float: left;
350 | margin: 0 4px 4px 0;
351 |
352 | .font-color {
353 | display: block;
354 | width: 16px;
355 | height: 16px;
356 | background: #dfdfdf;
357 | border-radius: 2px;
358 |
359 | &:hover {
360 | opacity: 0.8;
361 | }
362 |
363 | &.font-color-default {
364 | background: #333333;
365 | }
366 | }
367 |
368 | $font-colors: #E33737 #e28b41 #c8a732 #209361 #418caf #aa8773 #999999;
369 | $i: 1;
370 | @each $color in $font-colors {
371 | .font-color-#{$i} {
372 | background: $color;
373 | }
374 | $i: $i + 1;
375 | }
376 | }
377 | }
378 | }
379 |
380 | &.toolbar-menu-table {
381 | .menu-create-table {
382 | background: #ffffff;
383 | padding: 1px;
384 |
385 | table {
386 | border: none;
387 | border-collapse: collapse;
388 | border-spacing: 0;
389 | table-layout: fixed;
390 |
391 | td {
392 | padding: 0;
393 | cursor: pointer;
394 |
395 | &:before {
396 | width: 16px;
397 | height: 16px;
398 | border: 1px solid #ffffff;
399 | background: #f3f3f3;
400 | display: block;
401 | content: ''
402 | }
403 |
404 | &.selected:before {
405 | background: #cfcfcf;
406 | }
407 | }
408 | }
409 | }
410 |
411 | .menu-edit-table {
412 | display: none;
413 |
414 | ul {
415 | li {
416 | white-space: nowrap;
417 | }
418 | }
419 | }
420 | }
421 |
422 | &.toolbar-menu-image {
423 | .menu-item-upload-image {
424 | position: relative;
425 | overflow: hidden;
426 |
427 | input[type=file] {
428 | position: absolute;
429 | right: 0px;
430 | top: 0px;
431 | opacity: 0;
432 | font-size: 100px;
433 | cursor: pointer;
434 | }
435 | }
436 | }
437 |
438 | &.toolbar-menu-alignment {
439 | width: 100%;
440 | ul {
441 | min-width: 100%;
442 | }
443 | .menu-item {
444 | text-align: center;
445 | }
446 | }
447 | }
448 | }
449 |
450 | .simditor-popover {
451 | display: none;
452 | padding: 5px 8px 0;
453 | background: #ffffff;
454 | box-shadow: 0 1px 4px rgba(0,0,0,0.4);
455 | border-radius: 2px;
456 | position: absolute;
457 | z-index: 2;
458 |
459 | .settings-field {
460 | margin: 0 0 5px 0;
461 | font-size: 12px;
462 | height: 25px;
463 | line-height: 25px;
464 |
465 | label {
466 | display: inline-block;
467 | margin: 0 5px 0 0;
468 | }
469 |
470 | input[type=text] {
471 | display: inline-block;
472 | width: 200px;
473 | box-sizing: border-box;
474 | font-size: 12px;
475 |
476 | &.image-size {
477 | width: 83px;
478 | }
479 | }
480 |
481 | .times {
482 | display: inline-block;
483 | width: 26px;
484 | font-size: 12px;
485 | text-align: center;
486 | }
487 | }
488 |
489 | &.link-popover .btn-unlink,
490 | &.image-popover .btn-upload,
491 | &.image-popover .btn-restore {
492 | display: inline-block;
493 | margin: 0 0 0 5px;
494 | color: #333333;
495 | font-size: 14px;
496 | outline: 0;
497 |
498 | span {
499 | opacity: 0.6;
500 | }
501 |
502 | &:hover span {
503 | opacity: 1;
504 | }
505 | }
506 |
507 | &.image-popover .btn-upload {
508 | position: relative;
509 | display: inline-block;
510 | overflow: hidden;
511 | vertical-align: middle;
512 |
513 | input[type=file] {
514 | position: absolute;
515 | right: 0px;
516 | top: 0px;
517 | opacity: 0;
518 | height: 100%;
519 | width: 28px;
520 | }
521 | }
522 | }
523 |
524 | &.simditor-mobile {
525 | .simditor-wrapper.toolbar-floating .simditor-toolbar {
526 | position: absolute;
527 | top: 0;
528 | z-index: 10;
529 | box-shadow: 0 0 6px rgba(0,0,0,0.1);
530 | }
531 | }
532 | }
533 |
534 |
535 |
536 | .simditor .simditor-body, .editor-style {
537 | font-size: 16px;
538 | font-family: arial, sans-serif;
539 | line-height: 1.6;
540 | color: #333;
541 | outline: none;
542 | word-wrap: break-word;
543 |
544 | & > :first-child {
545 | margin-top: 0!important;
546 | }
547 |
548 | a{ color: #4298BA; text-decoration: none; word-break: break-all;}
549 | a:visited{ color: #4298BA; }
550 | a:hover{ color: #0F769F; }
551 | a:active{ color:#9E792E; }
552 | a:hover, a:active{ outline: 0; }
553 |
554 | h1,h2,h3,h4,h5,h6 {
555 | font-weight: normal;
556 | margin: 40px 0 20px;
557 | color: #000000;
558 | }
559 |
560 | h1 { font-size: 24px; }
561 | h2 { font-size: 22px; }
562 | h3 { font-size: 20px; }
563 | h4 { font-size: 18px; }
564 | h5 { font-size: 16px; }
565 | h6 { font-size: 16px; }
566 |
567 | p, div {
568 | word-wrap: break-word;
569 | margin: 0 0 15px 0;
570 | color: #333;
571 | word-wrap: break-word;
572 | }
573 |
574 | b, strong {
575 | font-weight: bold;
576 | }
577 |
578 | i, em {
579 | font-style: italic;
580 | }
581 |
582 | u {
583 | text-decoration: underline;
584 | }
585 |
586 | strike, del {
587 | text-decoration: line-through;
588 | }
589 |
590 | ul, ol {
591 | list-style:disc outside none;
592 | margin: 15px 0;
593 | padding: 0 0 0 40px;
594 | line-height: 1.6;
595 |
596 | ul, ol {
597 | padding-left: 30px;
598 | }
599 |
600 | ul {
601 | list-style: circle outside none;
602 |
603 | ul {
604 | list-style: square outside none;
605 | }
606 | }
607 | }
608 |
609 | ol {
610 | list-style:decimal;
611 | }
612 |
613 | blockquote {
614 | border-left: 6px solid #ddd;
615 | padding: 5px 0 5px 10px;
616 | margin: 15px 0 15px 15px;
617 |
618 | & > :first-child {
619 | margin-top: 0;
620 | }
621 | }
622 |
623 | code {
624 | display: inline-block;
625 | padding: 0 4px;
626 | margin: 0 5px;
627 | background: #eeeeee;
628 | border-radius: 3px;
629 | font-size: 13px;
630 | font-family: 'monaco', 'Consolas', "Liberation Mono", Courier, monospace;
631 | }
632 |
633 | pre {
634 | padding: 10px 5px 10px 10px;
635 | margin: 15px 0;
636 | display: block;
637 | line-height: 18px;
638 | background: #F0F0F0;
639 | border-radius: 3px;
640 | font-size:13px;
641 | font-family: 'monaco', 'Consolas', "Liberation Mono", Courier, monospace;
642 | white-space: pre;
643 | word-wrap: normal;
644 | overflow-x: auto;
645 |
646 | code {
647 | display: block;
648 | padding: 0;
649 | margin: 0;
650 | background: none;
651 | border-radius: 0;
652 | }
653 | }
654 |
655 | hr {
656 | display: block;
657 | height: 0px;
658 | border: 0;
659 | border-top: 1px solid #ccc;
660 | margin: 15px 0;
661 | padding: 0;
662 | }
663 |
664 | table {
665 | width: 100%;
666 | table-layout: fixed;
667 | border-collapse: collapse;
668 | border-spacing: 0;
669 | margin: 15px 0;
670 |
671 | thead {
672 | background-color: #f9f9f9;
673 | }
674 |
675 | td, th {
676 | min-width: 40px;
677 | height: 30px;
678 | border: 1px solid #ccc;
679 | vertical-align: top;
680 | padding: 2px 4px;
681 | text-align: left;
682 | box-sizing: border-box;
683 |
684 | &.active {
685 | background-color: #ffffee;
686 | }
687 | }
688 | }
689 |
690 |
691 | img {
692 | margin: 0 5px;
693 | vertical-align: middle;
694 | }
695 |
696 | }
697 |
--------------------------------------------------------------------------------
/simditor/static/simditor/styles/fonticon.scss:
--------------------------------------------------------------------------------
1 | @font-face{font-family:'Simditor';src:url(data:application/font-woff;charset=utf-8;base64,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) format('woff');font-weight:normal;font-style:normal}.simditor-icon{display:inline-block;font:normal normal normal 14px/1 'Simditor';font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0,0)}.simditor-icon-code:before{content:'\f000'}.simditor-icon-bold:before{content:'\f001'}.simditor-icon-italic:before{content:'\f002'}.simditor-icon-underline:before{content:'\f003'}.simditor-icon-times:before{content:'\f004'}.simditor-icon-strikethrough:before{content:'\f005'}.simditor-icon-list-ol:before{content:'\f006'}.simditor-icon-list-ul:before{content:'\f007'}.simditor-icon-quote-left:before{content:'\f008'}.simditor-icon-table:before{content:'\f009'}.simditor-icon-link:before{content:'\f00a'}.simditor-icon-picture-o:before{content:'\f00b'}.simditor-icon-minus:before{content:'\f00c'}.simditor-icon-indent:before{content:'\f00d'}.simditor-icon-outdent:before{content:'\f00e'}.simditor-icon-unlink:before{content:'\f00f'}.simditor-icon-caret-down:before{content:'\f010'}.simditor-icon-caret-right:before{content:'\f011'}.simditor-icon-upload:before{content:'\f012'}.simditor-icon-undo:before{content:'\f013'}.simditor-icon-smile-o:before{content:'\f014'}.simditor-icon-tint:before{content:'\f015'}.simditor-icon-font:before{content:'\f016'}.simditor-icon-html5:before{content:'\f017'}.simditor-icon-mark:before{content:'\f018'}.simditor-icon-align-center:before{content:'\f019'}.simditor-icon-align-left:before{content:'\f01a'}.simditor-icon-align-right:before{content:'\f01b'}.simditor-icon-font-minus:before{content:'\f01c'}.simditor-icon-markdown:before{content:'\f01d'}.simditor-icon-checklist:before{content:'\f01e'}
--------------------------------------------------------------------------------
/simditor/static/simditor/styles/simditor-checklist.css:
--------------------------------------------------------------------------------
1 | .simditor .simditor-body .simditor-checklist {
2 | margin: 15px 0;
3 | padding: 0 0 0 40px;
4 | line-height: 1.6;
5 | list-style-type: none;
6 | }
7 |
8 | .simditor .simditor-body .simditor-checklist > li {
9 | margin: 0;
10 | pointer-events: none;
11 | }
12 | .simditor .simditor-body .simditor-checklist > li::before {
13 | content: '';
14 | pointer-events: all;
15 | display: inline-block;
16 | margin: 0 5px 0 -25px;
17 | width: 20px;
18 | height: 20px;
19 | cursor: default;
20 | vertical-align: middle;
21 | background-image: url("data:image/gif;base64,R0lGODlhFAAUAPUAAP///9nZ2XV1dWNjY3Z2dv7+/mpqasbGxsPDw21tbfv7+2RkZM/Pz/X19crKymdnZ+/v725ubsvLy/Hx8XBwcO7u7nd3d83Nzezs7Hp6eoCAgNfX14SEhIqKitLS0uDg4I2NjZSUlNTU1Ojo6NXV1ZaWlp6entjY2J+fn6WlpeXl5ebm5qmpqY6OjvPz85CQkP39/Xt7e/Ly8t3d3dzc3P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAAA1ACwAAAAAFAAUAAAG/8BarVar1Wq1Wq1Wq9VqtVqtVqvVarVarVar1Wq1Wq1Wq9VqtVqtVqvVarVarVar1Wq1Wq1Wq9WAtVpAMBgMBoPBYEAI1Gq1Wq1WKxgOAAAAAAAAAIhEoVar1Wo1xYLRaDQajUaj4XgoarVarVaDACOSyWQymUwmEwkFUqvVarVaxXLBYDAYDAaDuWQqtVqtVqtVNIzNZrPZbDYbBqdSq9VqtVql4wF+Pp/P5/P5eECVWq1Wq9UqIdFoNBqNRqMRqVSp1Wq1Wq1i2kwmk8lkMpmcUJVarVar1SopFQAABAAAAABgxarUarVaraZoOVwul8vlcrkuL0WtVqvVajBHTGYgEAgEAoEg5oDVarVarVaDyWY0Gg1Io9FmMlitVqvVarVarVYoFAqFQqFQq9VqtVqtVqvVarVarVar1Wq1Wq1Wq9VqtVqtVqvVarUasFar1Wq1Wq1Wq9VqtVqtVqvVarVarVar1YIAOw==");
22 | }
23 | .simditor .simditor-body .simditor-checklist > li[checked]::before {
24 | background-image: url("data:image/gif;base64,R0lGODlhFAAUAPYAAAAAAHeHkD9QYB8wSOjo6Haw6C1huLbn8MfY8Ja42I630Ia48NjY2IefoJbH6Ja44H648D9CkCVZsE9XWFWY2D5wqI+foH6gwE9fYHeIoF93iPj4+J7P+J7A4IegyE54sPDw8I+nuB5BmAAHCEdXWC9BiFaAuFdveF2g4F9veB5JoA8PD12Y4GWg4CZRqKbI6GWo4BcoOK7Q8Cc4SDVwwAcPEEdQYA8YIDc/QBYykC1pwD9IWGaY0C8/SE2Q0B84UF6QyFWY4E2Q2D5omAcIGA8gMEZoiEZvkC5ZsE9ZmP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAABKACwAAAAAFAAUAAAH/4BKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKEys4SkpKSkpKSkpKSkpKSkpKShYAIyBKSkpKSkpKIUkRERERERERNwA2SkpKSkpKShslHggICAgICAEANyUbSkpKSkpKGzkoMjIyMjIdKwAVORtKSkpKSkogIhSAOz0ZMjI2ADZBIiBKSkpKSkogKkEaACsJFwArHUEqIEpKSkpKSiAuQSgxAD8xAEMoQS4gSkpKSkpKIEgoMDw1AAADMDAoSCBKSkpKSkogBigFBUcANTwFBS0GIEpKSkpKSiA0MAsLCzNHCwsLLTQgSkpKSkpKICYLHBwcDhwcgJYcHAsmIEpKSkpKShspCgcHBwcHBwcHCikbSkpKSkpKGxYYGBgYGBgYGBgYFhtKSkpKSkpKGyAMDAwMDAwMDCAbSkpKSkpKSkpKShsbGxsbGxsbSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkqASkpKSkpKSkpKSkpKSkpKSkpKSkpKSoEAOw==");
25 | }
--------------------------------------------------------------------------------
/simditor/static/simditor/styles/simditor-checklist.min.css:
--------------------------------------------------------------------------------
1 | .simditor .simditor-body .simditor-checklist{margin:15px 0;padding:0 0 0 40px;line-height:1.6;list-style-type:none}.simditor .simditor-body .simditor-checklist>li{margin:0;pointer-events:none}.simditor .simditor-body .simditor-checklist>li::before{content:'';pointer-events:all;display:inline-block;margin:0 5px 0 -25px;width:20px;height:20px;cursor:default;vertical-align:middle;background-image:url("data:image/gif;base64,R0lGODlhFAAUAPUAAP///9nZ2XV1dWNjY3Z2dv7+/mpqasbGxsPDw21tbfv7+2RkZM/Pz/X19crKymdnZ+/v725ubsvLy/Hx8XBwcO7u7nd3d83Nzezs7Hp6eoCAgNfX14SEhIqKitLS0uDg4I2NjZSUlNTU1Ojo6NXV1ZaWlp6entjY2J+fn6WlpeXl5ebm5qmpqY6OjvPz85CQkP39/Xt7e/Ly8t3d3dzc3P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAAA1ACwAAAAAFAAUAAAG/8BarVar1Wq1Wq1Wq9VqtVqtVqvVarVarVar1Wq1Wq1Wq9VqtVqtVqvVarVarVar1Wq1Wq1Wq9WAtVpAMBgMBoPBYEAI1Gq1Wq1WKxgOAAAAAAAAAIhEoVar1Wo1xYLRaDQajUaj4XgoarVarVaDACOSyWQymUwmEwkFUqvVarVaxXLBYDAYDAaDuWQqtVqtVqtVNIzNZrPZbDYbBqdSq9VqtVql4wF+Pp/P5/P5eECVWq1Wq9UqIdFoNBqNRqMRqVSp1Wq1Wq1i2kwmk8lkMpmcUJVarVar1SopFQAABAAAAABgxarUarVaraZoOVwul8vlcrkuL0WtVqvVajBHTGYgEAgEAoEg5oDVarVarVaDyWY0Gg1Io9FmMlitVqvVarVarVYoFAqFQqFQq9VqtVqtVqvVarVarVar1Wq1Wq1Wq9VqtVqtVqvVarUasFar1Wq1Wq1Wq9VqtVqtVqvVarVarVar1YIAOw==")}.simditor .simditor-body .simditor-checklist>li[checked]::before{background-image:url("data:image/gif;base64,R0lGODlhFAAUAPYAAAAAAHeHkD9QYB8wSOjo6Haw6C1huLbn8MfY8Ja42I630Ia48NjY2IefoJbH6Ja44H648D9CkCVZsE9XWFWY2D5wqI+foH6gwE9fYHeIoF93iPj4+J7P+J7A4IegyE54sPDw8I+nuB5BmAAHCEdXWC9BiFaAuFdveF2g4F9veB5JoA8PD12Y4GWg4CZRqKbI6GWo4BcoOK7Q8Cc4SDVwwAcPEEdQYA8YIDc/QBYykC1pwD9IWGaY0C8/SE2Q0B84UF6QyFWY4E2Q2D5omAcIGA8gMEZoiEZvkC5ZsE9ZmP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAABKACwAAAAAFAAUAAAH/4BKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKEys4SkpKSkpKSkpKSkpKSkpKShYAIyBKSkpKSkpKIUkRERERERERNwA2SkpKSkpKShslHggICAgICAEANyUbSkpKSkpKGzkoMjIyMjIdKwAVORtKSkpKSkogIhSAOz0ZMjI2ADZBIiBKSkpKSkogKkEaACsJFwArHUEqIEpKSkpKSiAuQSgxAD8xAEMoQS4gSkpKSkpKIEgoMDw1AAADMDAoSCBKSkpKSkogBigFBUcANTwFBS0GIEpKSkpKSiA0MAsLCzNHCwsLLTQgSkpKSkpKICYLHBwcDhwcgJYcHAsmIEpKSkpKShspCgcHBwcHBwcHCikbSkpKSkpKGxYYGBgYGBgYGBgYFhtKSkpKSkpKGyAMDAwMDAwMDCAbSkpKSkpKSkpKShsbGxsbGxsbSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkqASkpKSkpKSkpKSkpKSkpKSkpKSkpKSoEAOw==")}
--------------------------------------------------------------------------------
/simditor/static/simditor/styles/simditor-fullscreen.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'icomoon';
3 | src: url("../fonts/icomoon.eot?4vkjot");
4 | src: url("../fonts/icomoon.eot?#iefix4vkjot") format("embedded-opentype"), url("../fonts/icomoon.ttf?4vkjot") format("truetype"), url("../fonts/icomoon.woff?4vkjot") format("woff"), url("../fonts/icomoon.svg?4vkjot#icomoon") format("svg");
5 | font-weight: normal;
6 | font-style: normal;
7 | }
8 | [class^="icon-"], [class*=" icon-"] {
9 | font-family: 'icomoon';
10 | speak: none;
11 | font-style: normal;
12 | font-weight: normal;
13 | font-variant: normal;
14 | text-transform: none;
15 | line-height: 1;
16 | /* Better Font Rendering =========== */
17 | -webkit-font-smoothing: antialiased;
18 | -moz-osx-font-smoothing: grayscale;
19 | }
20 |
21 | .icon-fullscreen:before {
22 | content: "\e600";
23 | }
24 |
25 | .simditor-fullscreen {
26 | overflow: hidden;
27 | }
28 | .simditor-fullscreen .simditor {
29 | position: fixed;
30 | top: 0;
31 | left: 0;
32 | z-index: 9999;
33 | width: 100%;
34 | }
35 | .simditor-fullscreen .simditor .simditor-body {
36 | overflow: auto;
37 | }
--------------------------------------------------------------------------------
/simditor/static/simditor/styles/simditor-fullscreen.min.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:'icomoon';src:url("../fonts/icomoon.eot?4vkjot");src:url("../fonts/icomoon.eot?#iefix4vkjot") format("embedded-opentype"),url("../fonts/icomoon.ttf?4vkjot") format("truetype"),url("../fonts/icomoon.woff?4vkjot") format("woff"),url("../fonts/icomoon.svg?4vkjot#icomoon") format("svg");font-weight:normal;font-style:normal}[class^="icon-"],[class*=" icon-"]{font-family:'icomoon';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-fullscreen:before{content:"\e600"}.simditor-fullscreen{overflow:hidden}.simditor-fullscreen .simditor{position:fixed;top:0;left:0;z-index:9999;width:100%}.simditor-fullscreen .simditor .simditor-body{overflow:auto}
--------------------------------------------------------------------------------
/simditor/static/simditor/styles/simditor-markdown.css:
--------------------------------------------------------------------------------
1 | .simditor .markdown-editor {
2 | display: none;
3 | }
4 | .simditor .markdown-editor textarea {
5 | display: block;
6 | width: 100%;
7 | min-height: 200px;
8 | box-sizing: border-box;
9 | padding: 22px 15px 40px;
10 | border: none;
11 | border-bottom: 1px solid #dfdfdf;
12 | resize: none;
13 | outline: none;
14 | font-size: 16px;
15 | }
16 | .simditor.simditor-markdown .markdown-editor {
17 | display: block;
18 | }
19 | .simditor.simditor-markdown .simditor-body {
20 | min-height: 100px;
21 | background: #f3f3f3;
22 | }
23 | .simditor.simditor-markdown .simditor-placeholder {
24 | display: none !important;
25 | }
26 | .simditor .simditor-toolbar .toolbar-item.toolbar-item-markdown .simditor-icon {
27 | font-size: 18px;
28 | }
29 |
--------------------------------------------------------------------------------
/simditor/static/simditor/styles/simditor-markdown.min.css:
--------------------------------------------------------------------------------
1 | .simditor .markdown-editor{display:none}.simditor .markdown-editor textarea{display:block;width:100%;min-height:200px;box-sizing:border-box;padding:22px 15px 40px;border:0;border-bottom:1px solid #dfdfdf;resize:none;outline:0;font-size:16px}.simditor.simditor-markdown .markdown-editor{display:block}.simditor.simditor-markdown .simditor-body{min-height:100px;background:#f3f3f3}.simditor.simditor-markdown .simditor-placeholder{display:none!important}.simditor .simditor-toolbar .toolbar-item.toolbar-item-markdown .simditor-icon{font-size:18px}
--------------------------------------------------------------------------------
/simditor/static/simditor/styles/simditor.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | @import 'fonticon';
4 | @import 'editor';
5 |
--------------------------------------------------------------------------------
/simditor/templates/simditor/widget.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/simditor/urls.py:
--------------------------------------------------------------------------------
1 | """simditor urls."""
2 | from __future__ import absolute_import
3 |
4 | import django
5 |
6 | from django.conf import settings
7 | from django.conf.urls import static
8 | from django.contrib.admin.views.decorators import staff_member_required
9 |
10 | from . import views
11 |
12 | if django.VERSION >= (2, 0):
13 | # pylint disable=C0103
14 | from django.urls import path
15 | urlpatterns = [
16 | path('upload/', staff_member_required(views.UPLOAD),
17 | name='simditor_upload'),
18 | ]
19 | elif django.VERSION >= (1, 8):
20 | from django.conf.urls import url
21 | # pylint disable=C0103
22 | urlpatterns = [
23 | url(r'^upload/', staff_member_required(views.UPLOAD),
24 | name='simditor_upload'),
25 | ]
26 | else:
27 | from django.conf.urls import patterns, url # pylint disable=C0411
28 | # pylint disable=C0103
29 | urlpatterns = patterns(
30 | '',
31 | url(r'^upload/', staff_member_required(views.UPLOAD),
32 | name='simditor_upload'),
33 | )
34 |
35 | if settings.DEBUG:
36 | urlpatterns += static.static(settings.MEDIA_URL,
37 | document_root=settings.MEDIA_ROOT)
38 | urlpatterns += static.static(settings.STATIC_URL,
39 | document_root=settings.STATIC_ROOT)
40 |
--------------------------------------------------------------------------------
/simditor/utils.py:
--------------------------------------------------------------------------------
1 | """simditor utils."""
2 | from __future__ import absolute_import
3 |
4 | import os.path
5 | import random
6 |
7 | import string
8 |
9 | from django.core.files.storage import default_storage
10 | from django.template.defaultfilters import slugify
11 |
12 |
13 | class NotAnImageException(Exception):
14 | pass
15 |
16 |
17 | def get_random_string():
18 | """Get random string."""
19 | return ''.join(random.sample(string.ascii_lowercase * 6, 6))
20 |
21 |
22 | def get_slugified_name(filename):
23 | """get_slugified_name."""
24 | slugified = slugify(filename)
25 | return slugified or get_random_string()
26 |
27 |
28 | def slugify_filename(filename):
29 | """ Slugify filename """
30 | name, ext = os.path.splitext(filename)
31 | slugified = get_slugified_name(name)
32 | return slugified + ext
33 |
34 |
35 | def get_media_url(path):
36 | """
37 | Determine system file's media URL.
38 | """
39 | return default_storage.url(path)
40 |
41 |
42 | def is_valid_image_extension(file_path):
43 | """is_valid_image_extension."""
44 | valid_extensions = ['.jpeg', '.jpg', '.gif', '.png']
45 | _, extension = os.path.splitext(file_path)
46 | return extension.lower() in valid_extensions
47 |
--------------------------------------------------------------------------------
/simditor/views.py:
--------------------------------------------------------------------------------
1 | """simditor views."""
2 | from __future__ import absolute_import
3 |
4 | import os
5 | from datetime import datetime
6 |
7 | from django.conf import settings
8 | from django.core.files.storage import default_storage
9 |
10 | from django.http import JsonResponse
11 |
12 | from django.views import generic
13 | from django.views.decorators.csrf import csrf_exempt
14 |
15 | from . import utils, image_processing
16 |
17 |
18 | def get_upload_filename(upload_name):
19 | # Generate date based path to put uploaded file.
20 | date_path = datetime.now().strftime('%Y/%m/%d')
21 |
22 | # Complete upload path (upload_path + date_path).
23 | upload_path = os.path.join(settings.SIMDITOR_UPLOAD_PATH, date_path)
24 |
25 | if getattr(settings, 'SIMDITOR_UPLOAD_SLUGIFY_FILENAME', True):
26 | upload_name = utils.slugify_filename(upload_name)
27 |
28 | return default_storage.get_available_name(os.path.join(upload_path, upload_name))
29 |
30 |
31 | def upload_handler(request):
32 | files = request.FILES
33 |
34 | upload_config = settings.SIMDITOR_CONFIGS.get(
35 | 'upload', {'fileKey': 'upload'})
36 | filekey = upload_config.get('fileKey', 'upload')
37 |
38 | uploaded_file = files.get(filekey)
39 |
40 | if not uploaded_file:
41 | retdata = {'file_path': '', 'success': False,
42 | 'msg': '图片上传失败,无法获取到图片对象!'}
43 | return JsonResponse(retdata)
44 |
45 | image_size = upload_config.get('image_size')
46 | if image_size and uploaded_file.size > image_size:
47 | retdata = {'file_path': '', 'success': False,
48 | 'msg': '上传失败,已超出图片最大限制!'}
49 | return JsonResponse(retdata)
50 |
51 | backend = image_processing.get_backend()
52 |
53 | if not getattr(settings, 'SIMDITOR_ALLOW_NONIMAGE_FILES', True):
54 | try:
55 | backend.image_verify(uploaded_file)
56 | except utils.NotAnImageException:
57 | retdata = {'file_path': '', 'success': False,
58 | 'msg': '图片格式错误!'}
59 | return JsonResponse(retdata)
60 |
61 | filename = get_upload_filename(uploaded_file.name)
62 | saved_path = default_storage.save(filename, uploaded_file)
63 |
64 | url = utils.get_media_url(saved_path)
65 |
66 | is_api = settings.SIMDITOR_CONFIGS.get('is_api', False)
67 | url = request.META.get('HTTP_ORIGIN') + url if is_api else url
68 |
69 | retdata = {'file_path': url, 'success': True, 'msg': '上传成功!'}
70 |
71 | return JsonResponse(retdata)
72 |
73 |
74 | class ImageUploadView(generic.View):
75 | """ImageUploadView."""
76 |
77 | http_method_names = ['post']
78 |
79 | def post(self, request, **kwargs):
80 | """Post."""
81 | return upload_handler(request)
82 |
83 |
84 | UPLOAD = csrf_exempt(ImageUploadView.as_view())
85 |
--------------------------------------------------------------------------------
/simditor/widgets.py:
--------------------------------------------------------------------------------
1 | """simditor widgets."""
2 | from __future__ import absolute_import
3 |
4 | import django
5 | from django import forms
6 | from django.conf import settings
7 | from django.core.exceptions import ImproperlyConfigured
8 | from django.core.serializers.json import DjangoJSONEncoder
9 |
10 | from django.template.loader import render_to_string
11 | from django.utils.safestring import mark_safe
12 | from django.utils.html import conditional_escape
13 | from django.utils.functional import Promise
14 |
15 | try:
16 | # Django >=2.1
17 | from django.forms.widgets import get_default_renderer
18 | IS_NEW_WIDGET = True
19 | except ImportError:
20 | IS_NEW_WIDGET = False
21 |
22 | try:
23 | # Django >=1.7
24 | from django.forms.utils import flatatt
25 | except ImportError:
26 | # Django <1.7
27 | from django.forms.util import flatatt # pylint disable=E0611, E0401
28 |
29 | if django.VERSION >= (4, 0):
30 | from django.utils.encoding import force_str
31 | else:
32 | from django.utils.encoding import force_text as force_str
33 |
34 |
35 | class LazyEncoder(DjangoJSONEncoder):
36 | """LazyEncoder."""
37 |
38 | # pylint disable=E0202
39 | def default(self, obj):
40 | if isinstance(obj, Promise):
41 | return force_str(obj)
42 | return super(LazyEncoder, self).default(obj)
43 |
44 |
45 | JSON_ENCODE = LazyEncoder().encode
46 |
47 |
48 | FULL_TOOLBAR = [
49 | 'title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale',
50 | 'color', '|', 'ol', 'ul', 'blockquote', 'code', 'table', '|', 'link',
51 | 'image', 'hr', '|', 'indent', 'outdent', 'alignment', 'checklist',
52 | 'markdown', 'fullscreen'
53 | ]
54 |
55 | DEFAULT_TOOLBAR = [
56 | 'title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale',
57 | 'color', '|', 'ol', 'ul', 'blockquote', 'table', '|', 'link',
58 | 'image', 'hr', '|', 'indent', 'outdent', 'alignment'
59 | ]
60 |
61 | DEFAULT_CONFIG = {
62 | 'toolbar': DEFAULT_TOOLBAR,
63 | 'cleanPaste': True,
64 | 'tabIndent': True,
65 | 'pasteImage': True,
66 | 'upload': {
67 | 'url': '/',
68 | 'fileKey': 'file'
69 | }
70 | }
71 |
72 |
73 | class SimditorWidget(forms.Textarea):
74 | """
75 | Widget providing Simditor for Rich Text Editing.abs
76 | Supports direct image uploads and embed.
77 | """
78 | class Media:
79 | """Media."""
80 |
81 | css_list = [
82 | 'simditor/styles/simditor.min.css'
83 | ]
84 |
85 | if 'emoji' in settings.SIMDITOR_TOOLBAR:
86 | css_list.append('simditor/styles/simditor-emoji.css')
87 |
88 | if 'fullscreen' in settings.SIMDITOR_TOOLBAR:
89 | css_list.append('simditor/styles/simditor-fullscreen.min.css')
90 |
91 | if 'checklist' in settings.SIMDITOR_TOOLBAR:
92 | css_list.append('simditor/styles/simditor-checklist.min.css')
93 |
94 | if 'markdown' in settings.SIMDITOR_TOOLBAR:
95 | css_list.append('simditor/styles/simditor-markdown.min.css')
96 |
97 | css = {'all': tuple(settings.STATIC_URL + url for url in css_list)}
98 |
99 | jquery_list = ['simditor/scripts/jquery.min.js',
100 | 'simditor/scripts/module.min.js',
101 | 'simditor/scripts/hotkeys.min.js',
102 | 'simditor/scripts/uploader.min.js',
103 | 'simditor/scripts/simditor.min.js']
104 |
105 | if 'fullscreen' in settings.SIMDITOR_TOOLBAR:
106 | jquery_list.append('simditor/scripts/simditor-fullscreen.min.js')
107 |
108 | if 'checklist' in settings.SIMDITOR_TOOLBAR:
109 | jquery_list.append('simditor/scripts/simditor-checklist.min.js')
110 |
111 | if 'markdown' in settings.SIMDITOR_TOOLBAR:
112 | jquery_list.append('simditor/scripts/marked.min.js')
113 | jquery_list.append('simditor/scripts/to-markdown.min.js')
114 | jquery_list.append('simditor/scripts/simditor-markdown.min.js')
115 |
116 | if 'image' in settings.SIMDITOR_TOOLBAR:
117 | jquery_list.append('simditor/scripts/simditor-dropzone.min.js')
118 |
119 | if 'emoji' in settings.SIMDITOR_TOOLBAR:
120 | jquery_list.append('simditor/scripts/simditor-emoji.js')
121 |
122 | js = tuple(settings.STATIC_URL + url for url in jquery_list)
123 |
124 | try:
125 |
126 | js += (settings.STATIC_URL + 'simditor/simditor-init.js',)
127 | except AttributeError:
128 | raise ImproperlyConfigured("django-simditor requires \
129 | SIMDITOR_MEDIA_PREFIX setting. This setting specifies a \
130 | URL prefix to the ckeditor JS and CSS media (not \
131 | uploaded media). Make sure to use a trailing slash: \
132 | SIMDITOR_MEDIA_PREFIX = '/media/simditor/'")
133 |
134 | def __init__(self, *args, **kwargs):
135 | super(SimditorWidget, self).__init__(*args, **kwargs)
136 | # Setup config from defaults.
137 | self.config = DEFAULT_CONFIG.copy()
138 |
139 | # Try to get valid config from settings.
140 | configs = getattr(settings, 'SIMDITOR_CONFIGS', None)
141 | if configs:
142 | if isinstance(configs, dict):
143 | self.config.update(configs)
144 | else:
145 | raise ImproperlyConfigured(
146 | 'SIMDITOR_CONFIGS setting must be a dictionary type.')
147 |
148 | def build_attrs(self, base_attrs, extra_attrs=None, **kwargs):
149 | """
150 | Helper function for building an attribute dictionary.
151 | This is combination of the same method from Django<=1.10 and Django1.11
152 | """
153 | attrs = dict(base_attrs, **kwargs)
154 | if extra_attrs:
155 | attrs.update(extra_attrs)
156 | return attrs
157 |
158 | def render(self, name, value, attrs=None, renderer=None):
159 | if value is None:
160 | value = ''
161 | final_attrs = self.build_attrs(self.attrs, attrs, name=name)
162 |
163 | params = ('simditor/widget.html', {
164 | 'final_attrs': flatatt(final_attrs),
165 | 'value': conditional_escape(force_str(value)),
166 | 'id': final_attrs['id'],
167 | 'config': JSON_ENCODE(self.config)
168 | })
169 |
170 | if renderer is None and IS_NEW_WIDGET:
171 | renderer = get_default_renderer()
172 |
173 | data = renderer.render(*params) if IS_NEW_WIDGET else render_to_string(*params)
174 |
175 | return mark_safe(data)
176 |
--------------------------------------------------------------------------------
/simditor_demo/app/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/simditor_demo/app/__init__.py
--------------------------------------------------------------------------------
/simditor_demo/app/admin.py:
--------------------------------------------------------------------------------
1 | """demo admin."""
2 | from django.contrib import admin
3 |
4 | from app.models import News
5 |
6 |
7 | @admin.register(News)
8 | class NewsAdmin(admin.ModelAdmin):
9 | """NewsAdmin."""
10 |
--------------------------------------------------------------------------------
/simditor_demo/app/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class AppConfig(AppConfig):
5 | name = 'app'
6 |
--------------------------------------------------------------------------------
/simditor_demo/app/forms.py:
--------------------------------------------------------------------------------
1 | """app forms."""
2 | from __future__ import absolute_import
3 |
4 | from django import forms
5 |
6 | from simditor.fields import RichTextFormField
7 |
8 |
9 | class SimditorForm(forms.ModelForm):
10 | """SimditorForm."""
11 | content = RichTextFormField()
12 |
--------------------------------------------------------------------------------
/simditor_demo/app/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.2 on 2017-06-08 07:44
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import simditor.fields
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | initial = True
12 |
13 | dependencies = [
14 | ]
15 |
16 | operations = [
17 | migrations.CreateModel(
18 | name='News',
19 | fields=[
20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21 | ('content', simditor.fields.RichTextField()),
22 | ],
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/simditor_demo/app/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/simditor_demo/app/migrations/__init__.py
--------------------------------------------------------------------------------
/simditor_demo/app/models.py:
--------------------------------------------------------------------------------
1 | """demo."""
2 | from django.db import models
3 |
4 | from simditor.fields import RichTextField
5 |
6 |
7 | class News(models.Model):
8 | """News."""
9 | content = RichTextField()
10 |
--------------------------------------------------------------------------------
/simditor_demo/app/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/simditor_demo/app/views.py:
--------------------------------------------------------------------------------
1 | """app views."""
2 |
3 | from django import forms
4 |
5 | from django.views import generic
6 |
7 | from simditor.fields import RichTextFormField
8 | try:
9 | from django.urls import reverse
10 | except ImportError: # Django < 2.0
11 | from django.core.urlresolvers import reverse
12 |
13 |
14 | class SimditorForm(forms.Form):
15 | content = RichTextFormField()
16 |
17 |
18 | class IndexView(generic.FormView):
19 | form_class = SimditorForm
20 |
21 | template_name = 'index.html'
22 |
23 | def get_success_url(self):
24 | return reverse('simditor-form')
25 |
--------------------------------------------------------------------------------
/simditor_demo/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", "simditor_demo.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 |
--------------------------------------------------------------------------------
/simditor_demo/simditor_demo/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/istommao/django-simditor/026e06571382671a97f382a1ff4e1af8ad5048b6/simditor_demo/simditor_demo/__init__.py
--------------------------------------------------------------------------------
/simditor_demo/simditor_demo/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for simditor_demo project.
3 |
4 | Generated by 'django-admin startproject' using Django 1.11.2.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.11/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/1.11/ref/settings/
11 | """
12 |
13 | import os
14 | import tempfile
15 |
16 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
17 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
18 |
19 |
20 | # Quick-start development settings - unsuitable for production
21 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
22 |
23 | # SECURITY WARNING: keep the secret key used in production secret!
24 | SECRET_KEY = '8wpi^@j!glnnb#_(0&mrpn6@=2les0@loxnt*j0b*8u1k!&5$m'
25 |
26 | # SECURITY WARNING: don't run with debug turned on in production!
27 | DEBUG = True
28 |
29 | ALLOWED_HOSTS = []
30 |
31 |
32 | # Application definition
33 |
34 | INSTALLED_APPS = [
35 | 'django.contrib.admin',
36 | 'django.contrib.auth',
37 | 'django.contrib.contenttypes',
38 | 'django.contrib.sessions',
39 | 'django.contrib.messages',
40 | 'django.contrib.staticfiles',
41 |
42 | 'simditor',
43 | 'app'
44 | ]
45 |
46 | MIDDLEWARE = [
47 | 'django.middleware.security.SecurityMiddleware',
48 | 'django.contrib.sessions.middleware.SessionMiddleware',
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 | ]
55 |
56 | ROOT_URLCONF = 'simditor_demo.urls'
57 |
58 | TEMPLATES = [
59 | {
60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
61 | 'DIRS': ['templates'],
62 | 'APP_DIRS': True,
63 | 'OPTIONS': {
64 | 'context_processors': [
65 | 'django.template.context_processors.debug',
66 | 'django.template.context_processors.request',
67 | 'django.contrib.auth.context_processors.auth',
68 | 'django.contrib.messages.context_processors.messages',
69 | ],
70 | },
71 | },
72 | ]
73 |
74 | WSGI_APPLICATION = 'simditor_demo.wsgi.application'
75 |
76 |
77 | # Database
78 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
79 |
80 | DATABASES = {
81 | 'default': {
82 | 'ENGINE': 'django.db.backends.sqlite3',
83 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
84 | }
85 | }
86 |
87 |
88 | # Password validation
89 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
90 |
91 | AUTH_PASSWORD_VALIDATORS = [
92 | {
93 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
94 | },
95 | {
96 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
97 | },
98 | {
99 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
100 | },
101 | {
102 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
103 | },
104 | ]
105 |
106 |
107 | # Internationalization
108 | # https://docs.djangoproject.com/en/1.11/topics/i18n/
109 |
110 | LANGUAGE_CODE = 'en-us'
111 |
112 | TIME_ZONE = 'UTC'
113 |
114 | USE_I18N = True
115 |
116 | USE_L10N = True
117 |
118 | USE_TZ = True
119 |
120 |
121 | # Static files (CSS, JavaScript, Images)
122 | # https://docs.djangoproject.com/en/1.11/howto/static-files/
123 |
124 | STATIC_URL = '/static/'
125 | MEDIA_URL = '/media/'
126 | # STATIC_ROOT = os.path.join(tempfile.gettempdir(), 'sm_static')
127 | STATIC_ROOT = os.path.join(BASE_DIR, 'static')
128 |
129 | MEDIA_ROOT = os.path.join(tempfile.gettempdir(), 'sm_media')
130 |
131 | SIMDITOR_UPLOAD_PATH = 'uploads/'
132 | SIMDITOR_IMAGE_BACKEND = 'pillow'
133 | # SIMDITOR_JQUERY_URL = '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'
134 |
135 | SIMDITOR_TOOLBAR = [
136 | 'title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale',
137 | 'color', '|', 'ol', 'ul', 'blockquote', 'code', 'table', '|', 'link',
138 | 'image', 'hr', '|', 'indent', 'outdent', 'alignment',
139 | 'markdown', 'emoji', 'checklist', 'fullscreen'
140 | ]
141 |
142 | SIMDITOR_CONFIGS = {
143 | 'toolbar': SIMDITOR_TOOLBAR,
144 | 'upload': {
145 | 'url': '/simditor/upload/',
146 | 'fileKey': 'upload',
147 | 'image_size': 1024 * 1024 * 4 # max image size 4MB
148 | },
149 | 'emoji': {
150 | 'imagePath': '/static/simditor/images/emoji/'
151 | },
152 | 'is_api': False
153 | }
154 |
--------------------------------------------------------------------------------
/simditor_demo/simditor_demo/urls.py:
--------------------------------------------------------------------------------
1 | """simditor_demo URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.conf.urls import url, include
14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
15 | """
16 | from django.conf import settings
17 | from django.conf.urls import include, url
18 | from django.conf.urls.static import static
19 | from django.contrib import admin
20 | from django.views import generic
21 | from django.views.decorators.csrf import csrf_exempt
22 |
23 | from app.views import IndexView
24 |
25 | from simditor.views import upload_handler
26 |
27 |
28 | class ImageUploadView(generic.View):
29 | """ImageUploadView."""
30 |
31 | http_method_names = ['post']
32 |
33 | def post(self, request, **kwargs):
34 | """Post."""
35 | return upload_handler(request)
36 |
37 |
38 | # pylint disable=C0103
39 | urlpatterns = [
40 | url(r'^$', IndexView.as_view(), name='simditor-form'),
41 | url(r'^admin/', admin.site.urls),
42 | url(r'^simditor/upload', csrf_exempt(ImageUploadView.as_view())),
43 | ]
44 |
45 | urlpatterns += static(
46 | settings.STATIC_URL,
47 | document_root=settings.STATIC_ROOT
48 | )
49 |
50 | urlpatterns += static(
51 | settings.MEDIA_URL,
52 | document_root=settings.MEDIA_ROOT
53 | )
54 |
--------------------------------------------------------------------------------
/simditor_demo/simditor_demo/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for simditor_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/1.11/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", "simditor_demo.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/simditor_demo/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
8 |
14 |
15 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | skip_missing_interpreters=True
3 | envlist=
4 | py27-coverage-init
5 | {py27,py34}-django{18,19,110}
6 | py27-{lint,isort,coverage-report}
7 |
8 | [testenv]
9 | usedevelop=True
10 | setenv=
11 | DJANGO_SETTINGS_MODULE=ckeditor_demo.settings
12 | # DISPLAY = :0
13 | COVERAGE_FILE=.coverage.{envname}
14 | passenv = LC_ALL LANG TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH DISPLAY
15 | changedir = {toxinidir}
16 | commands= {envbindir}/coverage run manage.py test ckeditor_demo
17 | deps=
18 | coverage==4.2
19 | Pillow==3.2.0
20 | selenium==2.53.6
21 | django19: Django>=1.9,<1.10
22 | django18: Django>=1.8,<1.9
23 | django110: Django>=1.10,<1.11
24 |
25 | [testenv:py27-coverage-init]
26 | setenv =
27 | COVERAGE_FILE = .coverage
28 | commands =
29 | coverage erase
30 | deps =
31 | coverage==4.2
32 |
33 | [testenv:py27-coverage-report]
34 | setenv =
35 | COVERAGE_FILE = .coverage
36 | commands=
37 | coverage combine
38 | coverage report -m
39 | deps =
40 | coverage==4.2
41 |
42 |
43 | [testenv:py27-lint]
44 | commands = {envbindir}/flake8
45 | deps =
46 | flake8
47 |
48 | [testenv:py27-isort]
49 | commands = {envbindir}/isort -vb --recursive --check-only ckeditor ckeditor_demo
50 | deps =
51 | isort
52 |
--------------------------------------------------------------------------------