mirror of
https://github.com/Ionaru/easy-markdown-editor
synced 2025-09-24 16:40:55 -06:00
update from upstream
This commit is contained in:
commit
9796aaafef
53
.travis.yml
53
.travis.yml
@ -1,32 +1,33 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
|
- '12' # EOL: April 2022
|
||||||
- '11' # EOL: June 2019
|
- '11' # EOL: June 2019
|
||||||
- '10' # EOL: April 2021
|
- '10' # EOL: April 2021
|
||||||
- '8' # EOL: December 2019
|
- '8' # EOL: December 2019
|
||||||
- '6' # EOL: April 2019
|
- '6' # EOL: April 2019
|
||||||
script:
|
|
||||||
- npm run prepare
|
jobs:
|
||||||
- npm run test:types
|
include:
|
||||||
before_deploy:
|
- stage: deploy
|
||||||
- if [ "$TRAVIS_BRANCH" = master ] && [ "$TRAVIS_PULL_REQUEST" = false ]; then npm version prerelease --no-git-tag-version --preid "$TRAVIS_BUILD_NUMBER"; fi
|
node_js: "lts/*"
|
||||||
deploy:
|
script: skip
|
||||||
- provider: npm
|
before_deploy: if [ "$TRAVIS_BRANCH" = master ] && [ "$TRAVIS_PULL_REQUEST" = false ]; then npm version prerelease --no-git-tag-version --preid "$TRAVIS_BUILD_NUMBER"; fi
|
||||||
email: info@saturnserver.org
|
deploy:
|
||||||
api_key:
|
- provider: npm
|
||||||
secure: rp4P11u0Vvz6iTkC1uj9LfNVOJASnTjffpqpe9lhuC/php7+fdoYvZ4e1EwKj2RVbi7YNqZE6w+Y6fsxZk72N4RGVO6HROm6gNv2wl+qk0B1XwciONO9y5FhTcdZrsq5Vx5WdoZThs5CSkXpvtHiavAnAt1ufYjqKGBZOENdxJ40kkn9WdQG2WvG7iZWDlDpDoqof2uO9k89d2UuTG5DKAoMpN+4UH0Fr0gV0u11IcBeH7rlSo2btlMaMsSO9Nb10Zf1rC0USHfyrui/BKvVGeRh7FASYrHwjqt4bwqzKZlP5bZ4zGIPMYXXsGLcidxIvSsNIRp7cgkWvsywe8cIi5XzaM48afWsbMUfMgXi9BDNjK7vBiuPBnGWYS3ylJZn/7SvMuqsoj4De5GWrCJ5pTsEKD5yw5+iqQv7v2ZYhuN7/tTSoEy/BOMdN43zWquJp57LXkyFQ9esGoI0bfeYojV2BvcpwY/UFS27e/9bH+RBlXsLfP0kEtosVGZ6i3AuUKtsYOxo4QZSI4yHtP7fKsoCoJIvpW3hcWjrnI8N7IC18/KihsUByuMgDgTTXXtDKxLbNVjbiVvFJeuClwe1oc1uusY1v/EkNpGDFZX5zFEVv3zC76NaLB75kCUN3gGC0RRFk0J9i3k8qa42TLjbOqvxgRxOEtVeRxowBNrymIQ=
|
email: info@saturnserver.org
|
||||||
tag: next
|
api_key:
|
||||||
skip_cleanup: true
|
secure: rp4P11u0Vvz6iTkC1uj9LfNVOJASnTjffpqpe9lhuC/php7+fdoYvZ4e1EwKj2RVbi7YNqZE6w+Y6fsxZk72N4RGVO6HROm6gNv2wl+qk0B1XwciONO9y5FhTcdZrsq5Vx5WdoZThs5CSkXpvtHiavAnAt1ufYjqKGBZOENdxJ40kkn9WdQG2WvG7iZWDlDpDoqof2uO9k89d2UuTG5DKAoMpN+4UH0Fr0gV0u11IcBeH7rlSo2btlMaMsSO9Nb10Zf1rC0USHfyrui/BKvVGeRh7FASYrHwjqt4bwqzKZlP5bZ4zGIPMYXXsGLcidxIvSsNIRp7cgkWvsywe8cIi5XzaM48afWsbMUfMgXi9BDNjK7vBiuPBnGWYS3ylJZn/7SvMuqsoj4De5GWrCJ5pTsEKD5yw5+iqQv7v2ZYhuN7/tTSoEy/BOMdN43zWquJp57LXkyFQ9esGoI0bfeYojV2BvcpwY/UFS27e/9bH+RBlXsLfP0kEtosVGZ6i3AuUKtsYOxo4QZSI4yHtP7fKsoCoJIvpW3hcWjrnI8N7IC18/KihsUByuMgDgTTXXtDKxLbNVjbiVvFJeuClwe1oc1uusY1v/EkNpGDFZX5zFEVv3zC76NaLB75kCUN3gGC0RRFk0J9i3k8qa42TLjbOqvxgRxOEtVeRxowBNrymIQ=
|
||||||
on:
|
tag: next
|
||||||
node: 10
|
skip_cleanup: true
|
||||||
branch: master
|
on:
|
||||||
repo: Ionaru/easy-markdown-editor
|
branch: master
|
||||||
- provider: npm
|
repo: Ionaru/easy-markdown-editor
|
||||||
email: info@saturnserver.org
|
- provider: npm
|
||||||
api_key:
|
email: info@saturnserver.org
|
||||||
secure: rp4P11u0Vvz6iTkC1uj9LfNVOJASnTjffpqpe9lhuC/php7+fdoYvZ4e1EwKj2RVbi7YNqZE6w+Y6fsxZk72N4RGVO6HROm6gNv2wl+qk0B1XwciONO9y5FhTcdZrsq5Vx5WdoZThs5CSkXpvtHiavAnAt1ufYjqKGBZOENdxJ40kkn9WdQG2WvG7iZWDlDpDoqof2uO9k89d2UuTG5DKAoMpN+4UH0Fr0gV0u11IcBeH7rlSo2btlMaMsSO9Nb10Zf1rC0USHfyrui/BKvVGeRh7FASYrHwjqt4bwqzKZlP5bZ4zGIPMYXXsGLcidxIvSsNIRp7cgkWvsywe8cIi5XzaM48afWsbMUfMgXi9BDNjK7vBiuPBnGWYS3ylJZn/7SvMuqsoj4De5GWrCJ5pTsEKD5yw5+iqQv7v2ZYhuN7/tTSoEy/BOMdN43zWquJp57LXkyFQ9esGoI0bfeYojV2BvcpwY/UFS27e/9bH+RBlXsLfP0kEtosVGZ6i3AuUKtsYOxo4QZSI4yHtP7fKsoCoJIvpW3hcWjrnI8N7IC18/KihsUByuMgDgTTXXtDKxLbNVjbiVvFJeuClwe1oc1uusY1v/EkNpGDFZX5zFEVv3zC76NaLB75kCUN3gGC0RRFk0J9i3k8qa42TLjbOqvxgRxOEtVeRxowBNrymIQ=
|
api_key:
|
||||||
skip_cleanup: true
|
secure: rp4P11u0Vvz6iTkC1uj9LfNVOJASnTjffpqpe9lhuC/php7+fdoYvZ4e1EwKj2RVbi7YNqZE6w+Y6fsxZk72N4RGVO6HROm6gNv2wl+qk0B1XwciONO9y5FhTcdZrsq5Vx5WdoZThs5CSkXpvtHiavAnAt1ufYjqKGBZOENdxJ40kkn9WdQG2WvG7iZWDlDpDoqof2uO9k89d2UuTG5DKAoMpN+4UH0Fr0gV0u11IcBeH7rlSo2btlMaMsSO9Nb10Zf1rC0USHfyrui/BKvVGeRh7FASYrHwjqt4bwqzKZlP5bZ4zGIPMYXXsGLcidxIvSsNIRp7cgkWvsywe8cIi5XzaM48afWsbMUfMgXi9BDNjK7vBiuPBnGWYS3ylJZn/7SvMuqsoj4De5GWrCJ5pTsEKD5yw5+iqQv7v2ZYhuN7/tTSoEy/BOMdN43zWquJp57LXkyFQ9esGoI0bfeYojV2BvcpwY/UFS27e/9bH+RBlXsLfP0kEtosVGZ6i3AuUKtsYOxo4QZSI4yHtP7fKsoCoJIvpW3hcWjrnI8N7IC18/KihsUByuMgDgTTXXtDKxLbNVjbiVvFJeuClwe1oc1uusY1v/EkNpGDFZX5zFEVv3zC76NaLB75kCUN3gGC0RRFk0J9i3k8qa42TLjbOqvxgRxOEtVeRxowBNrymIQ=
|
||||||
on:
|
skip_cleanup: true
|
||||||
node: 10
|
on:
|
||||||
branch: master
|
branch: master
|
||||||
tags: true
|
repo: Ionaru/easy-markdown-editor
|
||||||
repo: Ionaru/easy-markdown-editor
|
tags: true
|
||||||
|
38
CHANGELOG.md
38
CHANGELOG.md
@ -1,11 +1,29 @@
|
|||||||
# EasyMDE Changelog
|
# EasyMDE Changelog
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to easymde will be documented in this file.
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
|
- Upload images functionality (Thanks to [@roipoussiere] and [@JeroenvO], [#71], [#101]).
|
||||||
|
- Allow custom image upload function (Thanks to [@sperezp], [#106]).
|
||||||
|
|
||||||
|
## [2.7.0] - 2019-07-13
|
||||||
|
### Added
|
||||||
|
- `previewClass` option for overwriting the preview screen class ([#99]).
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Updated dependencies to resolve potential security issue.
|
||||||
|
- Resolved small code style issues shown by new eslint rules.
|
||||||
|
|
||||||
|
## [2.6.1] - 2019-06-17
|
||||||
|
### Fixed
|
||||||
|
- Error when toggling between ordered and unordered lists (Thanks to [@roryok], [#93]).
|
||||||
|
- Keyboard shortcuts for custom actions not working (Thanks to [@ysykzheng], [#75]).
|
||||||
|
|
||||||
|
## [2.6.0] - 2019-04-15
|
||||||
|
### Added
|
||||||
- Contributing guide (Thanks to [@roipoussiere], [#54]).
|
- Contributing guide (Thanks to [@roipoussiere], [#54]).
|
||||||
- Issue templates.
|
- Issue templates.
|
||||||
- Standardized changelog file.
|
- Standardized changelog file.
|
||||||
@ -13,7 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
- Finish rewrite of README (Thanks to [@roipoussiere], [#54]).
|
- Finish rewrite of README (Thanks to [@roipoussiere], [#54]).
|
||||||
- Image and link prompt fill with "https://" by default.
|
- Image and link prompt fill with "https://" by default.
|
||||||
- Link to markdown guide to https://www.markdownguide.org/basic-syntax/.
|
- Link to markdown guide to <https://www.markdownguide.org/basic-syntax/>.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Backwards compatibility in the API with SimpleMDE 1.0.0 ([#41]).
|
- Backwards compatibility in the API with SimpleMDE 1.0.0 ([#41]).
|
||||||
@ -95,6 +113,7 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown
|
|||||||
- Cursor not always showing in "text" mode over the edit field
|
- Cursor not always showing in "text" mode over the edit field
|
||||||
|
|
||||||
<!-- Linked issues -->
|
<!-- Linked issues -->
|
||||||
|
[#99]: https://github.com/Ionaru/easy-markdown-editor/issues/99
|
||||||
[#45]: https://github.com/Ionaru/easy-markdown-editor/issues/45
|
[#45]: https://github.com/Ionaru/easy-markdown-editor/issues/45
|
||||||
[#44]: https://github.com/Ionaru/easy-markdown-editor/issues/44
|
[#44]: https://github.com/Ionaru/easy-markdown-editor/issues/44
|
||||||
[#41]: https://github.com/Ionaru/easy-markdown-editor/issues/41
|
[#41]: https://github.com/Ionaru/easy-markdown-editor/issues/41
|
||||||
@ -106,12 +125,22 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown
|
|||||||
[#9]: https://github.com/Ionaru/easy-markdown-editor/issues/9
|
[#9]: https://github.com/Ionaru/easy-markdown-editor/issues/9
|
||||||
|
|
||||||
<!-- Linked PRs -->
|
<!-- Linked PRs -->
|
||||||
|
[#106]: https://github.com/Ionaru/easy-markdown-editor/pull/106
|
||||||
|
[#101]: https://github.com/Ionaru/easy-markdown-editor/pull/101
|
||||||
|
[#93]: https://github.com/Ionaru/easy-markdown-editor/pull/93
|
||||||
|
[#75]: https://github.com/Ionaru/easy-markdown-editor/pull/75
|
||||||
|
[#71]: https://github.com/Ionaru/easy-markdown-editor/pull/71
|
||||||
[#54]: https://github.com/Ionaru/easy-markdown-editor/pull/54
|
[#54]: https://github.com/Ionaru/easy-markdown-editor/pull/54
|
||||||
[#31]: https://github.com/Ionaru/easy-markdown-editor/pull/31
|
[#31]: https://github.com/Ionaru/easy-markdown-editor/pull/31
|
||||||
[#27]: https://github.com/Ionaru/easy-markdown-editor/pull/27
|
[#27]: https://github.com/Ionaru/easy-markdown-editor/pull/27
|
||||||
[#19]: https://github.com/Ionaru/easy-markdown-editor/pull/19
|
[#19]: https://github.com/Ionaru/easy-markdown-editor/pull/19
|
||||||
|
|
||||||
<!-- Linked users -->
|
<!-- Linked users -->
|
||||||
|
[@sperezp]: https://github.com/sperezp
|
||||||
|
[@JeroenvO]: https://github.com/JeroenvO
|
||||||
|
[@sn3p]: https://github.com/sn3p
|
||||||
|
[@roryok]: https://github.com/roryok
|
||||||
|
[@ysykzheng]: https://github.com/ysykzheng
|
||||||
[@roipoussiere]: https://github.com/roipoussiere
|
[@roipoussiere]: https://github.com/roipoussiere
|
||||||
[@FranklinWhale]: https://github.com/FranklinWhale
|
[@FranklinWhale]: https://github.com/FranklinWhale
|
||||||
[@Furgas]: https://github.com/Furgas
|
[@Furgas]: https://github.com/Furgas
|
||||||
@ -123,7 +152,10 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown
|
|||||||
[@sne11ius]: https://github.com/sne11ius
|
[@sne11ius]: https://github.com/sne11ius
|
||||||
|
|
||||||
<!-- Linked versions -->
|
<!-- Linked versions -->
|
||||||
[Unreleased]: https://github.com/Ionaru/easy-markdown-editor/compare/2.5.1...HEAD
|
[Unreleased]: https://github.com/Ionaru/easy-markdown-editor/compare/2.7.0...HEAD
|
||||||
|
[2.7.0]: https://github.com/Ionaru/easy-markdown-editor/compare/2.6.1...2.7.0
|
||||||
|
[2.6.1]: https://github.com/Ionaru/easy-markdown-editor/compare/2.6.0...2.6.1
|
||||||
|
[2.6.0]: https://github.com/Ionaru/easy-markdown-editor/compare/2.5.1...2.6.0
|
||||||
[2.5.1]: https://github.com/Ionaru/easy-markdown-editor/compare/2.5.0...2.5.1
|
[2.5.1]: https://github.com/Ionaru/easy-markdown-editor/compare/2.5.0...2.5.1
|
||||||
[2.5.0]: https://github.com/Ionaru/easy-markdown-editor/compare/2.4.2...2.5.0
|
[2.5.0]: https://github.com/Ionaru/easy-markdown-editor/compare/2.4.2...2.5.0
|
||||||
[2.4.2]: https://github.com/Ionaru/easy-markdown-editor/compare/2.4.1...2.4.2
|
[2.4.2]: https://github.com/Ionaru/easy-markdown-editor/compare/2.4.1...2.4.2
|
||||||
|
28
README.md
28
README.md
@ -143,11 +143,35 @@ easyMDE.value('New input for **EasyMDE**');
|
|||||||
- **strikethrough**: If set to `false`, will not process GFM strikethrough syntax. Defaults to `true`.
|
- **strikethrough**: If set to `false`, will not process GFM strikethrough syntax. Defaults to `true`.
|
||||||
- **underscoresBreakWords**: If set to `true`, let underscores be a delimiter for separating words. Defaults to `false`.
|
- **underscoresBreakWords**: If set to `true`, let underscores be a delimiter for separating words. Defaults to `false`.
|
||||||
- **placeholder**: If set, displays a custom placeholder message.
|
- **placeholder**: If set, displays a custom placeholder message.
|
||||||
|
- **previewClass**: A string or array of strings that will be applied to the preview screen when activated. Defaults to `"editor-preview"`.
|
||||||
- **previewRender**: Custom function for parsing the plaintext Markdown and returning HTML. Used when user previews.
|
- **previewRender**: Custom function for parsing the plaintext Markdown and returning HTML. Used when user previews.
|
||||||
- **promptURLs**: If set to `true`, a JS alert window appears asking for the link or image URL. Defaults to `false`.
|
- **promptURLs**: If set to `true`, a JS alert window appears asking for the link or image URL. Defaults to `false`.
|
||||||
- **promptTexts**: Customize the text used to prompt for URLs.
|
- **promptTexts**: Customize the text used to prompt for URLs.
|
||||||
- **image**: The text to use when prompting for an image's URL. Defaults to `URL of the image:`.
|
- **image**: The text to use when prompting for an image's URL. Defaults to `URL of the image:`.
|
||||||
- **link**: The text to use when prompting for a link's URL. Defaults to `URL for the link:`.
|
- **link**: The text to use when prompting for a link's URL. Defaults to `URL for the link:`.
|
||||||
|
- **uploadImage**: If set to `true`, enables the image upload functionality, which can be triggered by drag&drop, copy-paste and through the browse-file window (opened when the user click on the *upload-image* icon). Defaults to `false`.
|
||||||
|
- **imageMaxSize**: Maximum image size in bytes, checked before upload (note: never trust client, always check image size at server-side). Defaults to `1024*1024*2` (2Mb).
|
||||||
|
- **imageAccept**: A comma-separated list of mime-types used to check image type before upload (note: never trust client, always check file types at server-side). Defaults to `image/png, image/jpeg`.
|
||||||
|
- **imageUploadFunction**: A custom function for handling the image upload. Using this function will render the options `imageMaxSize`, `imageAccept`, `imageUploadEndpoint` and `imageCSRFToken` ineffective.
|
||||||
|
- The function gets a file and onSuccess and onError callback functions as parameters. `onSuccess(imageUrl: string)` and `onError(errorMessage: string)`
|
||||||
|
- **imageUploadEndpoint**: The endpoint where the images data will be sent, via an asynchronous *POST* request. The server is supposed to save this image, and return a json response.
|
||||||
|
- if the request was successfully processed (HTTP 200-OK): `{"data": {"filePath": "<filePath>"}}` where *filePath* is the relative path of the image;
|
||||||
|
- otherwise: `{"error": "<errorCode>"}`, where *errorCode* can be `noFileGiven` (HTTP 400), `typeNotAllowed` (HTTP 415), `fileTooLarge` (HTTP 413) or `importError` (see *errorMessages* below). If *errorCode* is not one of the *errorMessages*, it is alerted unchanged to the user. This allows for server side error messages.
|
||||||
|
No default value.
|
||||||
|
- **imageCSRFToken**: CSRF token to include with AJAX call to upload image. For instance used with Django backend.
|
||||||
|
- **imageTexts**: Texts displayed to the user (mainly on the status bar) for the import image feature, where `#image_name#`, `#image_size#` and `#image_max_size#` will replaced by their respective values, that can be used for customization or internationalization:
|
||||||
|
- **sbInit**: Status message displayed initially if `uploadImage` is set to `true`. Defaults to `Attach files by drag and dropping or pasting from clipboard.`.
|
||||||
|
- **sbOnDragEnter**: Status message displayed when the user drags a file to the text area. Defaults to `Drop image to upload it.`.
|
||||||
|
- **sbOnDrop**: Status message displayed when the user drops a file in the text area. Defaults to `Uploading images #images_names#`.
|
||||||
|
- **sbProgress**: Status message displayed to show uploading progress. Defaults to `Uploading #file_name#: #progress#%`.
|
||||||
|
- **sbOnUploaded**: Status message displayed when the image has been uploaded. Defaults to `Uploaded #image_name#`.
|
||||||
|
- **sizeUnits**: A comma-separated list of units used to display messages with human-readable file sizes. Defaults to `b,Kb,Mb`.
|
||||||
|
- **errorMessages**: Errors displayed to the user, using the `errorCallback` option, where `#image_name#`, `#image_size#` and `#image_max_size#` will replaced by their respective values, that can be used for customization or internationalization:
|
||||||
|
- **noFileGiven**: The server did not receive any file from the user. Defaults to `You must select a file.`.
|
||||||
|
- **typeNotAllowed**: The user send a file type which doesn't match the `imageAccept` list, or the server returned this error code. Defaults to `This image type is not allowed.`.
|
||||||
|
- **fileTooLarge**: The size of the image being imported is bigger than the `imageMaxSize`, or if the server returned this error code. Defaults to `Image #image_name# is too big (#image_size#).\nMaximum file size is #image_max_size#.`.
|
||||||
|
- **importError**: An unexpected error occurred when uploading the image. Defaults to `Something went wrong when uploading the image #image_name#.`.
|
||||||
|
- **errorCallback**: A callback function used to define how to display an error message. Defaults to `function(errorMessage) {alert(errorMessage);};`.
|
||||||
- **renderingConfig**: Adjust settings for parsing the Markdown during previewing (not editing).
|
- **renderingConfig**: Adjust settings for parsing the Markdown during previewing (not editing).
|
||||||
- **codeSyntaxHighlighting**: If set to `true`, will highlight using [highlight.js](https://github.com/isagalaev/highlight.js). Defaults to `false`. To use this feature you must include highlight.js on your page or pass in using the `hljs` option. For example, include the script and the CSS files like:<br>`<script src="https://cdn.jsdelivr.net/highlight.js/latest/highlight.min.js"></script>`<br>`<link rel="stylesheet" href="https://cdn.jsdelivr.net/highlight.js/latest/styles/github.min.css">`
|
- **codeSyntaxHighlighting**: If set to `true`, will highlight using [highlight.js](https://github.com/isagalaev/highlight.js). Defaults to `false`. To use this feature you must include highlight.js on your page or pass in using the `hljs` option. For example, include the script and the CSS files like:<br>`<script src="https://cdn.jsdelivr.net/highlight.js/latest/highlight.min.js"></script>`<br>`<link rel="stylesheet" href="https://cdn.jsdelivr.net/highlight.js/latest/styles/github.min.css">`
|
||||||
- **hljs**: An injectible instance of [highlight.js](https://github.com/isagalaev/highlight.js). If you don't want to rely on the global namespace (`window.hljs`), you can provide an instance here. Defaults to `undefined`.
|
- **hljs**: An injectible instance of [highlight.js](https://github.com/isagalaev/highlight.js). If you don't want to rely on the global namespace (`window.hljs`), you can provide an instance here. Defaults to `undefined`.
|
||||||
@ -201,6 +225,10 @@ var editor = new EasyMDE({
|
|||||||
underscoresBreakWords: true,
|
underscoresBreakWords: true,
|
||||||
},
|
},
|
||||||
placeholder: "Type here...",
|
placeholder: "Type here...",
|
||||||
|
|
||||||
|
previewClass: "my-custom-styling",
|
||||||
|
previewClass: ["my-custom-styling", "more-custom-styling"],
|
||||||
|
|
||||||
previewRender: function(plainText) {
|
previewRender: function(plainText) {
|
||||||
return customMarkdownParser(plainText); // Returns HTML from a custom parser
|
return customMarkdownParser(plainText); // Returns HTML from a custom parser
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
var gulp = require('gulp');
|
var gulp = require('gulp');
|
||||||
var cleanCSS = require('gulp-clean-css');
|
var cleanCSS = require('gulp-clean-css');
|
||||||
var uglify = require('gulp-uglify');
|
var terser = require('gulp-terser');
|
||||||
var concat = require('gulp-concat');
|
var concat = require('gulp-concat');
|
||||||
var header = require('gulp-header');
|
var header = require('gulp-header');
|
||||||
var buffer = require('vinyl-buffer');
|
var buffer = require('vinyl-buffer');
|
||||||
@ -31,7 +31,7 @@ function scripts() {
|
|||||||
return browserify({entries: './src/js/easymde.js', standalone: 'EasyMDE'}).bundle()
|
return browserify({entries: './src/js/easymde.js', standalone: 'EasyMDE'}).bundle()
|
||||||
.pipe(source('easymde.min.js'))
|
.pipe(source('easymde.min.js'))
|
||||||
.pipe(buffer())
|
.pipe(buffer())
|
||||||
.pipe(uglify())
|
.pipe(terser())
|
||||||
.pipe(header(banner, {pkg: pkg}))
|
.pipe(header(banner, {pkg: pkg}))
|
||||||
.pipe(gulp.dest('./dist/'));
|
.pipe(gulp.dest('./dist/'));
|
||||||
}
|
}
|
||||||
|
710
package-lock.json
generated
710
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "easymde",
|
"name": "easymde",
|
||||||
"version": "2.5.1",
|
"version": "2.7.0",
|
||||||
"description": "A simple, beautiful, and embeddable JavaScript Markdown editor that easy to use. Features include autosaving and spell checking.",
|
"description": "A simple, beautiful, and embeddable JavaScript Markdown editor that easy to use. Features include autosaving and spell checking.",
|
||||||
"files": [
|
"files": [
|
||||||
"dist/**/*",
|
"dist/**/*",
|
||||||
@ -18,34 +18,30 @@
|
|||||||
"types": "types/easymde.d.ts",
|
"types": "types/easymde.d.ts",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": "Jeroen Akkerman",
|
"author": "Jeroen Akkerman",
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/ionaru/easy-markdown-editor/issues"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"codemirror": "^5.43.0",
|
"codemirror": "^5.48.0",
|
||||||
"codemirror-spell-checker": "1.1.2",
|
"codemirror-spell-checker": "1.1.2",
|
||||||
"marked": "^0.6.1"
|
"marked": "^0.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/codemirror": "0.0.72",
|
"@types/codemirror": "0.0.76",
|
||||||
"browserify": "^16.2.3",
|
"browserify": "^16.3.0",
|
||||||
"gulp": "^4.0.0",
|
"gulp": "^4.0.2",
|
||||||
"gulp-clean-css": "^4.0.0",
|
"gulp-clean-css": "^4.2.0",
|
||||||
"gulp-concat": "^2.6.1",
|
"gulp-concat": "^2.6.1",
|
||||||
"gulp-eslint": "^5.0.0",
|
"gulp-eslint": "^6.0.0",
|
||||||
"gulp-header": "^2.0.7",
|
"gulp-header": "^2.0.7",
|
||||||
"gulp-rename": "^1.4.0",
|
"gulp-rename": "^1.4.0",
|
||||||
"gulp-uglify": "^3.0.1",
|
"gulp-terser": "^1.2.0",
|
||||||
"typescript": "^3.3.3",
|
"gulp-uglify": "^3.0.2",
|
||||||
|
"typescript": "^3.5.3",
|
||||||
"vinyl-buffer": "^1.0.0",
|
"vinyl-buffer": "^1.0.0",
|
||||||
"vinyl-source-stream": "^2.0.0"
|
"vinyl-source-stream": "^2.0.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": "github:Ionaru/easy-markdown-editor",
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/ionaru/easy-markdown-editor"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "gulp",
|
"prepare": "gulp",
|
||||||
|
"test": "npm run test:types",
|
||||||
"test:types": "tsc --project types/tsconfig.json"
|
"test:types": "tsc --project types/tsconfig.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,14 +306,12 @@
|
|||||||
content: 'characters: '
|
content: 'characters: '
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-preview {
|
.editor-preview-full {
|
||||||
padding: 10px;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background: #fafafa;
|
|
||||||
z-index: 7;
|
z-index: 7;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
display: none;
|
display: none;
|
||||||
@ -321,13 +319,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.editor-preview-side {
|
.editor-preview-side {
|
||||||
padding: 10px;
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
top: 50px;
|
top: 50px;
|
||||||
right: 0;
|
right: 0;
|
||||||
background: #fafafa;
|
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
display: none;
|
display: none;
|
||||||
@ -344,21 +340,22 @@
|
|||||||
display: block
|
display: block
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-preview > p,
|
.editor-preview {
|
||||||
.editor-preview-side > p {
|
padding: 10px;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-preview > p {
|
||||||
margin-top: 0
|
margin-top: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-preview pre,
|
.editor-preview pre {
|
||||||
.editor-preview-side pre {
|
|
||||||
background: #eee;
|
background: #eee;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-preview table td,
|
.editor-preview table td,
|
||||||
.editor-preview table th,
|
.editor-preview table th {
|
||||||
.editor-preview-side table td,
|
|
||||||
.editor-preview-side table th {
|
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/*global require,module*/
|
|
||||||
'use strict';
|
'use strict';
|
||||||
var CodeMirror = require('codemirror');
|
var CodeMirror = require('codemirror');
|
||||||
require('codemirror/addon/edit/continuelist.js');
|
require('codemirror/addon/edit/continuelist.js');
|
||||||
@ -122,6 +121,11 @@ function createToolbarButton(options, enableTooltips, shortcuts) {
|
|||||||
el.setAttribute('type', 'button');
|
el.setAttribute('type', 'button');
|
||||||
enableTooltips = (enableTooltips == undefined) ? true : enableTooltips;
|
enableTooltips = (enableTooltips == undefined) ? true : enableTooltips;
|
||||||
|
|
||||||
|
// Properly hande custom shortcuts
|
||||||
|
if (options.name && options.name in shortcuts) {
|
||||||
|
bindings[options.name] = options.action;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.title && enableTooltips) {
|
if (options.title && enableTooltips) {
|
||||||
el.title = createTooltip(options.title, options.action, shortcuts);
|
el.title = createTooltip(options.title, options.action, shortcuts);
|
||||||
|
|
||||||
@ -287,7 +291,7 @@ function toggleFullScreen(editor) {
|
|||||||
if (/editor-preview-active-side/.test(sidebyside.className))
|
if (/editor-preview-active-side/.test(sidebyside.className))
|
||||||
toggleSideBySide(editor);
|
toggleSideBySide(editor);
|
||||||
|
|
||||||
if (editor.options.onToggleFullScreen) {
|
if (editor.options.onToggleFullScreen) {
|
||||||
editor.options.onToggleFullScreen(cm.getOption('fullScreen') || false);
|
editor.options.onToggleFullScreen(cm.getOption('fullScreen') || false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -384,9 +388,9 @@ function toggleCodeBlock(editor) {
|
|||||||
line: start_line_sel,
|
line: start_line_sel,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: end_line_sel,
|
line: end_line_sel,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var cm = editor.codemirror,
|
var cm = editor.codemirror,
|
||||||
@ -408,9 +412,9 @@ function toggleCodeBlock(editor) {
|
|||||||
line: cur_start.line,
|
line: cur_start.line,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: cur_start.line,
|
line: cur_start.line,
|
||||||
ch: 99999999999999,
|
ch: 99999999999999,
|
||||||
});
|
});
|
||||||
cur_start.ch--;
|
cur_start.ch--;
|
||||||
if (cur_start !== cur_end) {
|
if (cur_start !== cur_end) {
|
||||||
cur_end.ch--;
|
cur_end.ch--;
|
||||||
@ -469,24 +473,24 @@ function toggleCodeBlock(editor) {
|
|||||||
line: end_line,
|
line: end_line,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: end_line + (end_text ? 0 : 1),
|
line: end_line + (end_text ? 0 : 1),
|
||||||
ch: 0,
|
ch: 0,
|
||||||
});
|
});
|
||||||
cm.replaceRange(start_text, {
|
cm.replaceRange(start_text, {
|
||||||
line: start_line,
|
line: start_line,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: start_line + (start_text ? 0 : 1),
|
line: start_line + (start_text ? 0 : 1),
|
||||||
ch: 0,
|
ch: 0,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cm.setSelection({
|
cm.setSelection({
|
||||||
line: start_line + (start_text ? 1 : 0),
|
line: start_line + (start_text ? 1 : 0),
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: end_line + (start_text ? 1 : -1),
|
line: end_line + (start_text ? 1 : -1),
|
||||||
ch: 0,
|
ch: 0,
|
||||||
});
|
});
|
||||||
cm.focus();
|
cm.focus();
|
||||||
} else {
|
} else {
|
||||||
// no selection, search for ends of this fenced block
|
// no selection, search for ends of this fenced block
|
||||||
@ -522,16 +526,16 @@ function toggleCodeBlock(editor) {
|
|||||||
line: block_start,
|
line: block_start,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: block_start + 1,
|
line: block_start + 1,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
});
|
});
|
||||||
cm.replaceRange('', {
|
cm.replaceRange('', {
|
||||||
line: block_end - 1,
|
line: block_end - 1,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: block_end,
|
line: block_end,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
cm.focus();
|
cm.focus();
|
||||||
}
|
}
|
||||||
@ -710,6 +714,33 @@ function drawImage(editor) {
|
|||||||
_replaceSelection(cm, stat.image, options.insertTexts.image, url);
|
_replaceSelection(cm, stat.image, options.insertTexts.image, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action for opening the browse-file window to upload an image to a server.
|
||||||
|
* @param editor {EasyMDE} The EasyMDE object
|
||||||
|
*/
|
||||||
|
function drawUploadedImage(editor) {
|
||||||
|
// TODO: Draw the image template with a fake url? ie: ''
|
||||||
|
editor.openBrowseFileWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action executed after an image have been successfully imported on the server.
|
||||||
|
* @param editor {EasyMDE} The EasyMDE object
|
||||||
|
* @param url {string} The url of the uploaded image
|
||||||
|
*/
|
||||||
|
function afterImageUploaded(editor, url) {
|
||||||
|
var cm = editor.codemirror;
|
||||||
|
var stat = getState(cm);
|
||||||
|
var options = editor.options;
|
||||||
|
var imageName = url.substr(url.lastIndexOf('/') + 1);
|
||||||
|
_replaceSelection(cm, stat.image, options.insertTexts.uploadedImage, url);
|
||||||
|
// show uploaded image filename for 1000ms
|
||||||
|
editor.updateStatusBar('upload-image', editor.options.imageTexts.sbOnUploaded.replace('#image_name#', imageName));
|
||||||
|
setTimeout(function () {
|
||||||
|
editor.updateStatusBar('upload-image', editor.options.imageTexts.sbInit);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action for drawing a table.
|
* Action for drawing a table.
|
||||||
*/
|
*/
|
||||||
@ -821,9 +852,23 @@ function togglePreview(editor) {
|
|||||||
var toolbar_div = wrapper.previousSibling;
|
var toolbar_div = wrapper.previousSibling;
|
||||||
var toolbar = editor.options.toolbar ? editor.toolbarElements.preview : false;
|
var toolbar = editor.options.toolbar ? editor.toolbarElements.preview : false;
|
||||||
var preview = wrapper.lastChild;
|
var preview = wrapper.lastChild;
|
||||||
if (!preview || !/editor-preview/.test(preview.className)) {
|
if (!preview || !/editor-preview-full/.test(preview.className)) {
|
||||||
|
|
||||||
preview = document.createElement('div');
|
preview = document.createElement('div');
|
||||||
preview.className = 'editor-preview';
|
preview.className = 'editor-preview-full';
|
||||||
|
|
||||||
|
if (editor.options.previewClass) {
|
||||||
|
|
||||||
|
if (Array.isArray(editor.options.previewClass)) {
|
||||||
|
for (var i = 0; i < editor.options.previewClass.length; i++) {
|
||||||
|
preview.className += (' ' + editor.options.previewClass[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (typeof editor.options.previewClass === 'string') {
|
||||||
|
preview.className += (' ' + editor.options.previewClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wrapper.appendChild(preview);
|
wrapper.appendChild(preview);
|
||||||
}
|
}
|
||||||
if (/editor-preview-active/.test(preview.className)) {
|
if (/editor-preview-active/.test(preview.className)) {
|
||||||
@ -866,6 +911,7 @@ function _replaceSelection(cm, active, startEnd, url) {
|
|||||||
Object.assign(startPoint, cm.getCursor('start'));
|
Object.assign(startPoint, cm.getCursor('start'));
|
||||||
Object.assign(endPoint, cm.getCursor('end'));
|
Object.assign(endPoint, cm.getCursor('end'));
|
||||||
if (url) {
|
if (url) {
|
||||||
|
start = start.replace('#url#', url); // url is in start for upload-image
|
||||||
end = end.replace('#url#', url);
|
end = end.replace('#url#', url);
|
||||||
}
|
}
|
||||||
if (active) {
|
if (active) {
|
||||||
@ -951,9 +997,9 @@ function _toggleHeading(cm, direction, size) {
|
|||||||
line: i,
|
line: i,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: i,
|
line: i,
|
||||||
ch: 99999999999999,
|
ch: 99999999999999,
|
||||||
});
|
});
|
||||||
})(i);
|
})(i);
|
||||||
}
|
}
|
||||||
cm.focus();
|
cm.focus();
|
||||||
@ -990,13 +1036,27 @@ function _toggleLine(cm, name) {
|
|||||||
var map = {
|
var map = {
|
||||||
'quote': '>',
|
'quote': '>',
|
||||||
'unordered-list': '*',
|
'unordered-list': '*',
|
||||||
'ordered-list': 'd+.',
|
'ordered-list': '\\d+.',
|
||||||
};
|
};
|
||||||
var rt = new RegExp(map[name]);
|
var rt = new RegExp(map[name]);
|
||||||
|
|
||||||
return char && rt.test(char);
|
return char && rt.test(char);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var _toggle = function (name, text, untoggleOnly) {
|
||||||
|
var arr = listRegexp.exec(text);
|
||||||
|
var char = _getChar(name, line);
|
||||||
|
if (arr !== null) {
|
||||||
|
if (_checkChar(name, arr[2])) {
|
||||||
|
char = '';
|
||||||
|
}
|
||||||
|
text = arr[1] + char + arr[3] + text.replace(whitespacesRegexp, '').replace(repl[name], '$1');
|
||||||
|
} else if (untoggleOnly == false) {
|
||||||
|
text = char + ' ' + text;
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
};
|
||||||
|
|
||||||
var line = 1;
|
var line = 1;
|
||||||
for (var i = startPoint.line; i <= endPoint.line; i++) {
|
for (var i = startPoint.line; i <= endPoint.line; i++) {
|
||||||
(function (i) {
|
(function (i) {
|
||||||
@ -1004,25 +1064,22 @@ function _toggleLine(cm, name) {
|
|||||||
if (stat[name]) {
|
if (stat[name]) {
|
||||||
text = text.replace(repl[name], '$1');
|
text = text.replace(repl[name], '$1');
|
||||||
} else {
|
} else {
|
||||||
var arr = listRegexp.exec(text);
|
// If we're toggling unordered-list formatting, check if the current line
|
||||||
var char = _getChar(name, line);
|
// is part of an ordered-list, and if so, untoggle that first.
|
||||||
if (arr !== null) {
|
// Workaround for https://github.com/Ionaru/easy-markdown-editor/issues/92
|
||||||
if (_checkChar(name, arr[2])) {
|
if (name == 'unordered-list') {
|
||||||
char = '';
|
text = _toggle('ordered-list', text, true);
|
||||||
}
|
|
||||||
text = arr[1] + char + arr[3] + text.replace(whitespacesRegexp, '').replace(repl[name], '$1');
|
|
||||||
} else {
|
|
||||||
text = char + ' ' + text;
|
|
||||||
}
|
}
|
||||||
|
text = _toggle(name, text, false);
|
||||||
line += 1;
|
line += 1;
|
||||||
}
|
}
|
||||||
cm.replaceRange(text, {
|
cm.replaceRange(text, {
|
||||||
line: i,
|
line: i,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: i,
|
line: i,
|
||||||
ch: 99999999999999,
|
ch: 99999999999999,
|
||||||
});
|
});
|
||||||
})(i);
|
})(i);
|
||||||
}
|
}
|
||||||
cm.focus();
|
cm.focus();
|
||||||
@ -1061,9 +1118,9 @@ function _toggleBlock(editor, type, start_chars, end_chars) {
|
|||||||
line: startPoint.line,
|
line: startPoint.line,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: startPoint.line,
|
line: startPoint.line,
|
||||||
ch: 99999999999999,
|
ch: 99999999999999,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (type == 'bold' || type == 'strikethrough') {
|
if (type == 'bold' || type == 'strikethrough') {
|
||||||
startPoint.ch -= 2;
|
startPoint.ch -= 2;
|
||||||
@ -1113,16 +1170,34 @@ function _cleanBlock(cm) {
|
|||||||
line: line,
|
line: line,
|
||||||
ch: 0,
|
ch: 0,
|
||||||
}, {
|
}, {
|
||||||
line: line,
|
line: line,
|
||||||
ch: 99999999999999,
|
ch: 99999999999999,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a number of bytes to a human-readable file size.
|
||||||
|
* @param bytes {integer} A number of bytes, as integer. Ex: 421137
|
||||||
|
* @param units {number[]} An array of human-readable units, ie. ['b', 'Kb', 'Mb']
|
||||||
|
* @returns string A human-readable file size. Ex: '412Kb'
|
||||||
|
*/
|
||||||
|
function humanFileSize(bytes, units) {
|
||||||
|
if (Math.abs(bytes) < 1024) {
|
||||||
|
return '' + bytes + units[0];
|
||||||
|
}
|
||||||
|
var u = 0;
|
||||||
|
do {
|
||||||
|
bytes /= 1024;
|
||||||
|
++u;
|
||||||
|
} while (Math.abs(bytes) >= 1024 && u < units.length);
|
||||||
|
return '' + bytes.toFixed(1) + units[u];
|
||||||
|
}
|
||||||
|
|
||||||
// Merge the properties of one object into another.
|
// Merge the properties of one object into another.
|
||||||
function _mergeProperties(target, source) {
|
function _mergeProperties(target, source) {
|
||||||
for (var property in source) {
|
for (var property in source) {
|
||||||
if (source.hasOwnProperty(property)) {
|
if (Object.prototype.hasOwnProperty.call(source, property)) {
|
||||||
if (source[property] instanceof Array) {
|
if (source[property] instanceof Array) {
|
||||||
target[property] = source[property].concat(target[property] instanceof Array ? target[property] : []);
|
target[property] = source[property].concat(target[property] instanceof Array ? target[property] : []);
|
||||||
} else if (
|
} else if (
|
||||||
@ -1276,6 +1351,12 @@ var toolbarBuiltInButtons = {
|
|||||||
title: 'Insert Image',
|
title: 'Insert Image',
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
'upload-image': {
|
||||||
|
name: 'upload-image',
|
||||||
|
action: drawUploadedImage,
|
||||||
|
className: 'fa fa-image',
|
||||||
|
title: 'Import an image',
|
||||||
|
},
|
||||||
'table': {
|
'table': {
|
||||||
name: 'table',
|
name: 'table',
|
||||||
action: drawTable,
|
action: drawTable,
|
||||||
@ -1350,6 +1431,8 @@ var toolbarBuiltInButtons = {
|
|||||||
var insertTexts = {
|
var insertTexts = {
|
||||||
link: ['[', '](#url#)'],
|
link: ['[', '](#url#)'],
|
||||||
image: [''],
|
image: [''],
|
||||||
|
uploadedImage: ['', ''],
|
||||||
|
// uploadedImage: ['\n', ''], // TODO: New line insertion doesn't work here.
|
||||||
table: ['', '\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n'],
|
table: ['', '\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n'],
|
||||||
horizontalRule: ['', '\n\n-----\n\n'],
|
horizontalRule: ['', '\n\n-----\n\n'],
|
||||||
};
|
};
|
||||||
@ -1365,6 +1448,31 @@ var blockStyles = {
|
|||||||
'italic': '*',
|
'italic': '*',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Texts displayed to the user (mainly on the status bar) for the import image
|
||||||
|
* feature. Can be used for customization or internationalization.
|
||||||
|
*/
|
||||||
|
var imageTexts = {
|
||||||
|
sbInit: 'Attach files by drag and dropping or pasting from clipboard.',
|
||||||
|
sbOnDragEnter: 'Drop image to upload it.',
|
||||||
|
sbOnDrop: 'Uploading image #images_names#...',
|
||||||
|
sbProgress: 'Uploading #file_name#: #progress#%',
|
||||||
|
sbOnUploaded: 'Uploaded #image_name#',
|
||||||
|
sizeUnits: 'b,Kb,Mb',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Errors displayed to the user, using the `errorCallback` option. Can be used for
|
||||||
|
* customization or internationalization.
|
||||||
|
*/
|
||||||
|
var errorMessages = {
|
||||||
|
noFileGiven: 'You must select a file.',
|
||||||
|
typeNotAllowed: 'This image type is not allowed.',
|
||||||
|
fileTooLarge: 'Image #image_name# is too big (#image_size#).\n' +
|
||||||
|
'Maximum file size is #image_max_size#.',
|
||||||
|
importError: 'Something went wrong when uploading the image #image_name#.',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface of EasyMDE.
|
* Interface of EasyMDE.
|
||||||
*/
|
*/
|
||||||
@ -1420,7 +1528,7 @@ function EasyMDE(options) {
|
|||||||
|
|
||||||
// Loop over the built in buttons, to get the preferred order
|
// Loop over the built in buttons, to get the preferred order
|
||||||
for (var key in toolbarBuiltInButtons) {
|
for (var key in toolbarBuiltInButtons) {
|
||||||
if (toolbarBuiltInButtons.hasOwnProperty(key)) {
|
if (Object.prototype.hasOwnProperty.call(toolbarBuiltInButtons, key)) {
|
||||||
if (key.indexOf('separator-') != -1) {
|
if (key.indexOf('separator-') != -1) {
|
||||||
options.toolbar.push('|');
|
options.toolbar.push('|');
|
||||||
}
|
}
|
||||||
@ -1432,10 +1540,18 @@ function EasyMDE(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Editor preview styling class.
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(options, 'previewClass')) {
|
||||||
|
options.previewClass = 'editor-preview';
|
||||||
|
}
|
||||||
|
|
||||||
// Handle status bar
|
// Handle status bar
|
||||||
if (!options.hasOwnProperty('status')) {
|
if (!Object.prototype.hasOwnProperty.call(options, 'status')) {
|
||||||
options.status = ['autosave', 'lines', 'words', 'cursor'];
|
options.status = ['autosave', 'lines', 'words', 'cursor'];
|
||||||
|
|
||||||
|
if (options.uploadImage) {
|
||||||
|
options.status.unshift('upload-image');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1471,6 +1587,17 @@ function EasyMDE(options) {
|
|||||||
|
|
||||||
options.minHeight = options.minHeight || '300px';
|
options.minHeight = options.minHeight || '300px';
|
||||||
|
|
||||||
|
options.errorCallback = options.errorCallback || function (errorMessage) {
|
||||||
|
alert(errorMessage);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Import-image default configuration
|
||||||
|
options.uploadImage = options.uploadImage || false;
|
||||||
|
options.imageMaxSize = options.imageMaxSize || 2097152; // 1024 * 1024 * 2
|
||||||
|
options.imageAccept = options.imageAccept || 'image/png, image/jpeg';
|
||||||
|
options.imageTexts = extend({}, imageTexts, options.imageTexts || {});
|
||||||
|
options.errorMessages = extend({}, errorMessages, options.errorMessages || {});
|
||||||
|
|
||||||
|
|
||||||
// Change unique_id to uniqueId for backwards compatibility
|
// Change unique_id to uniqueId for backwards compatibility
|
||||||
if (options.autosave != undefined && options.autosave.unique_id != undefined && options.autosave.unique_id != '')
|
if (options.autosave != undefined && options.autosave.unique_id != undefined && options.autosave.unique_id != '')
|
||||||
@ -1491,8 +1618,107 @@ function EasyMDE(options) {
|
|||||||
if (options.initialValue && (!this.options.autosave || this.options.autosave.foundSavedValue !== true)) {
|
if (options.initialValue && (!this.options.autosave || this.options.autosave.foundSavedValue !== true)) {
|
||||||
this.value(options.initialValue);
|
this.value(options.initialValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.uploadImage) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.codemirror.on('dragenter', function (cm, event) {
|
||||||
|
self.updateStatusBar('upload-image', self.options.imageTexts.sbOnDragEnter);
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
this.codemirror.on('dragend', function (cm, event) {
|
||||||
|
self.updateStatusBar('upload-image', self.options.imageTexts.sbInit);
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
this.codemirror.on('dragleave', function (cm, event) {
|
||||||
|
self.updateStatusBar('upload-image', self.options.imageTexts.sbInit);
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.codemirror.on('dragover', function (cm, event) {
|
||||||
|
self.updateStatusBar('upload-image', self.options.imageTexts.sbOnDragEnter);
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.codemirror.on('drop', function (cm, event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
if (options.imageUploadFunction) {
|
||||||
|
self.uploadImagesUsingCustomFunction(options.imageUploadFunction, event.dataTransfer.files);
|
||||||
|
} else {
|
||||||
|
self.uploadImages(event.dataTransfer.files);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.codemirror.on('paste', function (cm, event) {
|
||||||
|
if (options.imageUploadFunction) {
|
||||||
|
self.uploadImagesUsingCustomFunction(options.imageUploadFunction, event.clipboardData.files);
|
||||||
|
} else {
|
||||||
|
self.uploadImages(event.clipboardData.files);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload asynchronously a list of images to a server.
|
||||||
|
*
|
||||||
|
* Can be triggered by:
|
||||||
|
* - drag&drop;
|
||||||
|
* - copy-paste;
|
||||||
|
* - the browse-file window (opened when the user clicks on the *upload-image* icon).
|
||||||
|
* @param {FileList} files The files to upload the the server.
|
||||||
|
* @param [onSuccess] {function} see EasyMDE.prototype.uploadImage
|
||||||
|
* @param [onError] {function} see EasyMDE.prototype.uploadImage
|
||||||
|
*/
|
||||||
|
EasyMDE.prototype.uploadImages = function (files, onSuccess, onError) {
|
||||||
|
var names = [];
|
||||||
|
for (var i = 0; i < files.length; i++) {
|
||||||
|
names.push(files[i].name);
|
||||||
|
this.uploadImage(files[i], onSuccess, onError);
|
||||||
|
}
|
||||||
|
this.updateStatusBar('upload-image', this.options.imageTexts.sbOnDrop.replace('#images_names#', names.join(', ')));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload asynchronously a list of images to a server.
|
||||||
|
*
|
||||||
|
* Can be triggered by:
|
||||||
|
* - drag&drop;
|
||||||
|
* - copy-paste;
|
||||||
|
* - the browse-file window (opened when the user clicks on the *upload-image* icon).
|
||||||
|
* @param imageUploadFunction {Function} The custom function to upload the image passed in options.
|
||||||
|
* @param {FileList} files The files to upload the the server.
|
||||||
|
*/
|
||||||
|
EasyMDE.prototype.uploadImagesUsingCustomFunction = function (imageUploadFunction, files) {
|
||||||
|
var names = [];
|
||||||
|
for (var i = 0; i < files.length; i++) {
|
||||||
|
names.push(files[i].name);
|
||||||
|
this.uploadImageUsingCustomFunction(imageUploadFunction, files[i]);
|
||||||
|
}
|
||||||
|
this.updateStatusBar('upload-image', this.options.imageTexts.sbOnDrop.replace('#images_names#', names.join(', ')));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an item in the status bar.
|
||||||
|
* @param itemName {string} The name of the item to update (ie. 'upload-image', 'autosave', etc.).
|
||||||
|
* @param content {string} the new content of the item to write in the status bar.
|
||||||
|
*/
|
||||||
|
EasyMDE.prototype.updateStatusBar = function (itemName, content) {
|
||||||
|
var matchingClasses = this.gui.statusbar.getElementsByClassName(itemName);
|
||||||
|
if (matchingClasses.length === 1) {
|
||||||
|
this.gui.statusbar.getElementsByClassName(itemName)[0].textContent = content;
|
||||||
|
} else if (matchingClasses.length === 0) {
|
||||||
|
console.log('EasyMDE: status bar item ' + itemName + ' was not found.');
|
||||||
|
} else {
|
||||||
|
console.log('EasyMDE: Several status bar items named ' + itemName + ' was found.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default markdown render.
|
* Default markdown render.
|
||||||
*/
|
*/
|
||||||
@ -1563,7 +1789,12 @@ EasyMDE.prototype.render = function (el) {
|
|||||||
if (options.shortcuts[key] !== null && bindings[key] !== null) {
|
if (options.shortcuts[key] !== null && bindings[key] !== null) {
|
||||||
(function (key) {
|
(function (key) {
|
||||||
keyMaps[fixShortcut(options.shortcuts[key])] = function () {
|
keyMaps[fixShortcut(options.shortcuts[key])] = function () {
|
||||||
bindings[key](self);
|
var action = bindings[key];
|
||||||
|
if (typeof action === 'function') {
|
||||||
|
action(self);
|
||||||
|
} else if (typeof action === 'string') {
|
||||||
|
window.open(action, '_blank');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
})(key);
|
})(key);
|
||||||
}
|
}
|
||||||
@ -1682,22 +1913,22 @@ EasyMDE.prototype.autosave = function () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.options.autosave.binded !== true) {
|
if (this.options.autosave.binded !== true) {
|
||||||
if (easyMDE.element.form != null && easyMDE.element.form != undefined) {
|
if (easyMDE.element.form != null && easyMDE.element.form != undefined) {
|
||||||
easyMDE.element.form.addEventListener('submit', function () {
|
easyMDE.element.form.addEventListener('submit', function () {
|
||||||
clearTimeout(easyMDE.autosaveTimeoutId);
|
clearTimeout(easyMDE.autosaveTimeoutId);
|
||||||
easyMDE.autosaveTimeoutId = undefined;
|
easyMDE.autosaveTimeoutId = undefined;
|
||||||
|
|
||||||
localStorage.removeItem('smde_' + easyMDE.options.autosave.uniqueId);
|
localStorage.removeItem('smde_' + easyMDE.options.autosave.uniqueId);
|
||||||
|
|
||||||
// Restart autosaving in case the submit will be cancelled down the line
|
// Restart autosaving in case the submit will be cancelled down the line
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
easyMDE.autosave();
|
easyMDE.autosave();
|
||||||
}, easyMDE.options.autosave.delay || 10000);
|
}, easyMDE.options.autosave.delay || 10000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.options.autosave.binded = true;
|
this.options.autosave.binded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.autosave.loaded !== true) {
|
if (this.options.autosave.loaded !== true) {
|
||||||
@ -1751,6 +1982,152 @@ EasyMDE.prototype.clearAutosavedValue = function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the browse-file window to upload an image to a server.
|
||||||
|
* @param [onSuccess] {function} see EasyMDE.prototype.uploadImage
|
||||||
|
* @param [onError] {function} see EasyMDE.prototype.uploadImage
|
||||||
|
*/
|
||||||
|
EasyMDE.prototype.openBrowseFileWindow = function (onSuccess, onError) {
|
||||||
|
var self = this;
|
||||||
|
var imageInput = this.gui.toolbar.getElementsByClassName('imageInput')[0];
|
||||||
|
imageInput.click(); //dispatchEvent(new MouseEvent('click')); // replaced with click() for IE11 compatibility.
|
||||||
|
function onChange(event) {
|
||||||
|
self.uploadImages(event.target.files, onSuccess, onError);
|
||||||
|
imageInput.removeEventListener('change', onChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
imageInput.addEventListener('change', onChange);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload an image to the server.
|
||||||
|
*
|
||||||
|
* @param file {File} The image to upload, as a HTML5 File object (https://developer.mozilla.org/en-US/docs/Web/API/File)
|
||||||
|
* @param [onSuccess] {function} A callback function to execute after the image has been successfully uploaded, with one parameter:
|
||||||
|
* - url (string): The URL of the uploaded image.
|
||||||
|
* @param [onError] {function} A callback function to execute when the image upload fails, with one parameter:
|
||||||
|
* - error (string): the detailed error to display to the user (based on messages from options.errorMessages).
|
||||||
|
*/
|
||||||
|
EasyMDE.prototype.uploadImage = function (file, onSuccess, onError) {
|
||||||
|
var self = this;
|
||||||
|
onSuccess = onSuccess || function onSuccess(imageUrl) {
|
||||||
|
afterImageUploaded(self, imageUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
function onErrorSup(errorMessage) {
|
||||||
|
// show error on status bar and reset after 10000ms
|
||||||
|
self.updateStatusBar('upload-image', errorMessage);
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
self.updateStatusBar('upload-image', self.options.imageTexts.sbInit);
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
// run custom error handler
|
||||||
|
if (onError && typeof onError === 'function') {
|
||||||
|
onError(errorMessage);
|
||||||
|
}
|
||||||
|
// run error handler from options, this alerts the message.
|
||||||
|
self.options.errorCallback(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillErrorMessage(errorMessage) {
|
||||||
|
var units = self.options.imageTexts.sizeUnits.split(',');
|
||||||
|
return errorMessage
|
||||||
|
.replace('#image_name#', file.name)
|
||||||
|
.replace('#image_size#', humanFileSize(file.size, units))
|
||||||
|
.replace('#image_max_size#', humanFileSize(self.options.imageMaxSize, units));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.size > this.options.imageMaxSize) {
|
||||||
|
onErrorSup(fillErrorMessage(this.options.errorMessages.fileTooLarge));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append('image', file);
|
||||||
|
|
||||||
|
// insert CSRF token if provided in config.
|
||||||
|
if (self.options.imageCSRFToken) {
|
||||||
|
formData.append('csrfmiddlewaretoken', self.options.imageCSRFToken);
|
||||||
|
}
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.upload.onprogress = function (event) {
|
||||||
|
if (event.lengthComputable) {
|
||||||
|
var progress = '' + Math.round((event.loaded * 100) / event.total);
|
||||||
|
self.updateStatusBar('upload-image', self.options.imageTexts.sbProgress.replace('#file_name#', file.name).replace('#progress#', progress));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
request.open('POST', this.options.imageUploadEndpoint);
|
||||||
|
|
||||||
|
request.onload = function () {
|
||||||
|
try {
|
||||||
|
var response = JSON.parse(this.responseText);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('EasyMDE: The server did not return a valid json.');
|
||||||
|
onErrorSup(fillErrorMessage(self.options.errorMessages.importError));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.status === 200 && response && !response.error && response.data && response.data.filePath) {
|
||||||
|
onSuccess(window.location.origin + '/' + response.data.filePath);
|
||||||
|
} else {
|
||||||
|
if (response.error && response.error in self.options.errorMessages) { // preformatted error message
|
||||||
|
onErrorSup(fillErrorMessage(self.options.errorMessages[response.error]));
|
||||||
|
} else if (response.error) { // server side generated error message
|
||||||
|
onErrorSup(fillErrorMessage(response.error));
|
||||||
|
} else { //unknown error
|
||||||
|
console.error('EasyMDE: Received an unexpected response after uploading the image.'
|
||||||
|
+ this.status + ' (' + this.statusText + ')');
|
||||||
|
onErrorSup(fillErrorMessage(self.options.errorMessages.importError));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onerror = function (event) {
|
||||||
|
console.error('EasyMDE: An unexpected error occurred when trying to upload the image.'
|
||||||
|
+ event.target.status + ' (' + event.target.statusText + ')');
|
||||||
|
onErrorSup(self.options.errorMessages.importError);
|
||||||
|
};
|
||||||
|
|
||||||
|
request.send(formData);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload an image to the server using a custom upload function.
|
||||||
|
*
|
||||||
|
* @param imageUploadFunction {Function} The custom function to upload the image passed in options
|
||||||
|
* @param file {File} The image to upload, as a HTML5 File object (https://developer.mozilla.org/en-US/docs/Web/API/File).
|
||||||
|
*/
|
||||||
|
EasyMDE.prototype.uploadImageUsingCustomFunction = function (imageUploadFunction, file) {
|
||||||
|
var self = this;
|
||||||
|
function onSuccess(imageUrl) {
|
||||||
|
afterImageUploaded(self, imageUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onError(errorMessage) {
|
||||||
|
var filledErrorMessage = fillErrorMessage(errorMessage);
|
||||||
|
// show error on status bar and reset after 10000ms
|
||||||
|
self.updateStatusBar('upload-image', filledErrorMessage);
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
self.updateStatusBar('upload-image', self.options.imageTexts.sbInit);
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
// run error handler from options, this alerts the message.
|
||||||
|
self.options.errorCallback(filledErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillErrorMessage(errorMessage) {
|
||||||
|
var units = self.options.imageTexts.sizeUnits.split(',');
|
||||||
|
return errorMessage
|
||||||
|
.replace('#image_name#', file.name)
|
||||||
|
.replace('#image_size#', humanFileSize(file.size, units))
|
||||||
|
.replace('#image_max_size#', humanFileSize(self.options.imageMaxSize, units));
|
||||||
|
}
|
||||||
|
|
||||||
|
imageUploadFunction(file, onSuccess, onError);
|
||||||
|
};
|
||||||
|
|
||||||
EasyMDE.prototype.createSideBySide = function () {
|
EasyMDE.prototype.createSideBySide = function () {
|
||||||
var cm = this.codemirror;
|
var cm = this.codemirror;
|
||||||
var wrapper = cm.getWrapperElement();
|
var wrapper = cm.getWrapperElement();
|
||||||
@ -1759,6 +2136,19 @@ EasyMDE.prototype.createSideBySide = function () {
|
|||||||
if (!preview || !/editor-preview-side/.test(preview.className)) {
|
if (!preview || !/editor-preview-side/.test(preview.className)) {
|
||||||
preview = document.createElement('div');
|
preview = document.createElement('div');
|
||||||
preview.className = 'editor-preview-side';
|
preview.className = 'editor-preview-side';
|
||||||
|
|
||||||
|
if (this.options.previewClass) {
|
||||||
|
|
||||||
|
if (Array.isArray(this.options.previewClass)) {
|
||||||
|
for (var i = 0; i < this.options.previewClass.length; i++) {
|
||||||
|
preview.className += (' ' + this.options.previewClass[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (typeof this.options.previewClass === 'string') {
|
||||||
|
preview.className += (' ' + this.options.previewClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wrapper.parentNode.insertBefore(preview, wrapper.nextSibling);
|
wrapper.parentNode.insertBefore(preview, wrapper.nextSibling);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1869,6 +2259,20 @@ EasyMDE.prototype.createToolbar = function (items) {
|
|||||||
|
|
||||||
toolbarData[item.name || item] = el;
|
toolbarData[item.name || item] = el;
|
||||||
bar.appendChild(el);
|
bar.appendChild(el);
|
||||||
|
|
||||||
|
// Create the input element (ie. <input type='file'>), used among
|
||||||
|
// with the 'import-image' icon to open the browse-file window.
|
||||||
|
if (item.name === 'upload-image') {
|
||||||
|
var imageInput = document.createElement('input');
|
||||||
|
imageInput.className = 'imageInput';
|
||||||
|
imageInput.type = 'file';
|
||||||
|
imageInput.multiple = true;
|
||||||
|
imageInput.name = 'image';
|
||||||
|
imageInput.accept = self.options.imageAccept;
|
||||||
|
imageInput.style.display = 'none';
|
||||||
|
imageInput.style.opacity = 0;
|
||||||
|
bar.appendChild(imageInput);
|
||||||
|
}
|
||||||
})(items[i]);
|
})(items[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1911,11 +2315,10 @@ EasyMDE.prototype.createStatusbar = function (status) {
|
|||||||
var options = this.options;
|
var options = this.options;
|
||||||
var cm = this.codemirror;
|
var cm = this.codemirror;
|
||||||
|
|
||||||
|
|
||||||
// Make sure the status variable is valid
|
// Make sure the status variable is valid
|
||||||
if (!status || status.length === 0)
|
if (!status || status.length === 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Set up the built-in items
|
// Set up the built-in items
|
||||||
var items = [];
|
var items = [];
|
||||||
@ -1965,6 +2368,10 @@ EasyMDE.prototype.createStatusbar = function (status) {
|
|||||||
el.setAttribute('id', 'autosaved');
|
el.setAttribute('id', 'autosaved');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} else if (name === 'upload-image') {
|
||||||
|
defaultValue = function (el) {
|
||||||
|
el.innerHTML = options.imageTexts.sbInit;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
// Create new instance
|
// Create new instance
|
||||||
|
import EasyMDE = require('./easymde');
|
||||||
|
|
||||||
const editor = new EasyMDE({
|
const editor = new EasyMDE({
|
||||||
autoDownloadFontAwesome: false,
|
autoDownloadFontAwesome: false,
|
||||||
element: document.getElementById('mdEditor')!,
|
element: document.getElementById('mdEditor')!,
|
||||||
@ -7,6 +9,7 @@ const editor = new EasyMDE({
|
|||||||
drawTable: 'Cmd-Alt-T',
|
drawTable: 'Cmd-Alt-T',
|
||||||
toggleFullScreen: null
|
toggleFullScreen: null
|
||||||
},
|
},
|
||||||
|
previewClass: 'my-custom-class',
|
||||||
spellChecker: false,
|
spellChecker: false,
|
||||||
onToggleFullScreen: (full: boolean) => {
|
onToggleFullScreen: (full: boolean) => {
|
||||||
console.log('FullscreenToggled', full);
|
console.log('FullscreenToggled', full);
|
||||||
@ -28,3 +31,87 @@ editor.codemirror.setOption('readOnly', true);
|
|||||||
EasyMDE.toggleItalic = (editor: EasyMDE) => {
|
EasyMDE.toggleItalic = (editor: EasyMDE) => {
|
||||||
console.log('SomeButtonOverride');
|
console.log('SomeButtonOverride');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const editor2 = new EasyMDE({
|
||||||
|
autoDownloadFontAwesome: undefined,
|
||||||
|
previewClass: ['my-custom-class', 'some-other-class'],
|
||||||
|
toolbar: [{
|
||||||
|
name: 'bold',
|
||||||
|
action: EasyMDE.toggleBold,
|
||||||
|
className: 'fa fa-bolt',
|
||||||
|
title: 'Bold',
|
||||||
|
}, '|', { // Separator
|
||||||
|
name: 'alert',
|
||||||
|
action: (editor: EasyMDE) => {
|
||||||
|
alert('This is from a custom button action!');
|
||||||
|
// Custom functions have access to the `editor` instance.
|
||||||
|
},
|
||||||
|
className: 'fa fa-star',
|
||||||
|
title: 'A Custom Button',
|
||||||
|
noDisable: undefined,
|
||||||
|
noMobile: false,
|
||||||
|
}, '|', {
|
||||||
|
name: 'link',
|
||||||
|
action: 'https://github.com/Ionaru/easy-markdown-editor',
|
||||||
|
className: 'fa fab fa-github',
|
||||||
|
title: 'A Custom Link',
|
||||||
|
noDisable: true,
|
||||||
|
noMobile: true,
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
editor2.clearAutosavedValue();
|
||||||
|
|
||||||
|
const editorImages = new EasyMDE({
|
||||||
|
uploadImage: true,
|
||||||
|
imageAccept: 'image/png, image/bmp',
|
||||||
|
imageCSRFToken: undefined,
|
||||||
|
imageMaxSize: 10485760,
|
||||||
|
imageUploadEndpoint: 'https://my.domain/image-upload/',
|
||||||
|
imageTexts: {
|
||||||
|
sbInit: 'Drag & drop images!',
|
||||||
|
sbOnDragEnter: 'Let it go, let it go',
|
||||||
|
sbOnDrop: 'Uploading...',
|
||||||
|
sbProgress: 'Uploading... (#progress#)',
|
||||||
|
sbOnUploaded: 'Upload complete!',
|
||||||
|
sizeUnits: 'b,Kb,Mb'
|
||||||
|
},
|
||||||
|
errorMessages: {
|
||||||
|
noFileGiven: 'Please select a file',
|
||||||
|
typeNotAllowed: 'This file type is not allowed!',
|
||||||
|
fileTooLarge: 'Image too big',
|
||||||
|
importError: 'Something went oops!',
|
||||||
|
},
|
||||||
|
errorCallback: (errorMessage) => {
|
||||||
|
console.error(errorMessage);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const editorImagesCustom = new EasyMDE({
|
||||||
|
uploadImage: true,
|
||||||
|
imageAccept: 'image/png, image/bmp',
|
||||||
|
imageCSRFToken: undefined,
|
||||||
|
imageMaxSize: 10485760,
|
||||||
|
imageUploadFunction: (file: File, onSuccess, onError) => {
|
||||||
|
console.log(file);
|
||||||
|
onSuccess('http://image.url/9.png');
|
||||||
|
onError('Failed because reasons.');
|
||||||
|
},
|
||||||
|
imageTexts: {
|
||||||
|
sbInit: 'Drag & drop images!',
|
||||||
|
sbOnDragEnter: 'Let it go, let it go',
|
||||||
|
sbOnDrop: 'Uploading...',
|
||||||
|
sbProgress: 'Uploading... (#progress#)',
|
||||||
|
sbOnUploaded: 'Upload complete!',
|
||||||
|
sizeUnits: 'b,Kb,Mb'
|
||||||
|
},
|
||||||
|
errorMessages: {
|
||||||
|
noFileGiven: 'Please select a file',
|
||||||
|
typeNotAllowed: 'This file type is not allowed!',
|
||||||
|
fileTooLarge: 'Image too big',
|
||||||
|
importError: 'Something went oops!',
|
||||||
|
},
|
||||||
|
errorCallback: (errorMessage) => {
|
||||||
|
console.error(errorMessage);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
27
types/easymde.d.ts
vendored
27
types/easymde.d.ts
vendored
@ -86,6 +86,22 @@ declare namespace EasyMDE {
|
|||||||
noMobile?: boolean;
|
noMobile?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ImageTextsOptions {
|
||||||
|
sbInit?: string;
|
||||||
|
sbOnDragEnter?: string;
|
||||||
|
sbOnDrop?: string;
|
||||||
|
sbProgress?: string;
|
||||||
|
sbOnUploaded?: string;
|
||||||
|
sizeUnits?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImageErrorTextsOptions {
|
||||||
|
noFileGiven?: string;
|
||||||
|
typeNotAllowed?: string;
|
||||||
|
fileTooLarge?: string;
|
||||||
|
importError?: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface Options {
|
interface Options {
|
||||||
autoDownloadFontAwesome?: boolean;
|
autoDownloadFontAwesome?: boolean;
|
||||||
autofocus?: boolean;
|
autofocus?: boolean;
|
||||||
@ -101,6 +117,7 @@ declare namespace EasyMDE {
|
|||||||
minHeight?: string;
|
minHeight?: string;
|
||||||
parsingConfig?: ParsingOptions;
|
parsingConfig?: ParsingOptions;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
previewClass?: string | ReadonlyArray<string>;
|
||||||
previewRender?: (markdownPlaintext: string, previewElement: HTMLElement) => string;
|
previewRender?: (markdownPlaintext: string, previewElement: HTMLElement) => string;
|
||||||
promptURLs?: boolean;
|
promptURLs?: boolean;
|
||||||
renderingConfig?: RenderingOptions;
|
renderingConfig?: RenderingOptions;
|
||||||
@ -114,6 +131,16 @@ declare namespace EasyMDE {
|
|||||||
toolbarTips?: boolean;
|
toolbarTips?: boolean;
|
||||||
onToggleFullScreen?: (goingIntoFullScreen: boolean) => void;
|
onToggleFullScreen?: (goingIntoFullScreen: boolean) => void;
|
||||||
theme?: string;
|
theme?: string;
|
||||||
|
|
||||||
|
uploadImage?: boolean;
|
||||||
|
imageMaxSize?: number;
|
||||||
|
imageAccept?: string;
|
||||||
|
imageUploadFunction?: (file: File, onSuccess: (url: string) => void, onError: (error: string) => void) => void;
|
||||||
|
imageUploadEndpoint?: string;
|
||||||
|
imageCSRFToken?: string;
|
||||||
|
imageTexts?: ImageTextsOptions;
|
||||||
|
errorMessages?: ImageErrorTextsOptions;
|
||||||
|
errorCallback?: (errorMessage: string) => void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user