mirror of
https://github.com/Ionaru/easy-markdown-editor
synced 2025-06-29 22:21:04 -06:00
Update everything & fix prettier/eslint errors
This commit is contained in:
parent
1e9986c0e3
commit
cbf0f6e387
@ -1,3 +0,0 @@
|
||||
coverage
|
||||
dist
|
||||
node_modules
|
14
.eslintrc
14
.eslintrc
@ -1,14 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": ["@ionaru", "prettier"],
|
||||
"rules": {
|
||||
"jest/no-deprecated-functions": "off",
|
||||
"jest/unbound-method": "off",
|
||||
"jest/require-hook": "off",
|
||||
"import/extensions": "off",
|
||||
"import/no-unresolved": "off",
|
||||
"unicorn/no-null": "off",
|
||||
"@typescript-eslint/member-ordering": "off",
|
||||
"@typescript-eslint/explicit-member-accessibility": "off"
|
||||
}
|
||||
}
|
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
@ -2,8 +2,8 @@
|
||||
|
||||
### I'm submitting a...
|
||||
|
||||
- [x] Bug report
|
||||
- [ ] Feature request
|
||||
- [x] Bug report
|
||||
- [ ] Feature request
|
||||
|
||||
### Reproduction steps
|
||||
|
||||
|
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
title: ""
|
||||
labels: Bug
|
||||
assignees: ''
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
@ -25,9 +25,9 @@ If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Version information**
|
||||
|
||||
- OS: [e.g. Windows, MacOS]
|
||||
- Browser: [e.g. Chrome 72]
|
||||
- EasyMDE version: [e.g. 2.5.1]
|
||||
- OS: [e.g. Windows, MacOS]
|
||||
- Browser: [e.g. Chrome 72]
|
||||
- EasyMDE version: [e.g. 2.5.1]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
title: ""
|
||||
labels: Feature
|
||||
assignees: ''
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
|
4
.github/ISSUE_TEMPLATE/question.md
vendored
4
.github/ISSUE_TEMPLATE/question.md
vendored
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question if anything is unclear
|
||||
title: ''
|
||||
title: ""
|
||||
labels: Question
|
||||
assignees: ''
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Describe your question**
|
||||
|
62
.github/workflows/cd.yaml
vendored
62
.github/workflows/cd.yaml
vendored
@ -1,48 +1,48 @@
|
||||
name: Test & Deploy
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- "*"
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: current
|
||||
steps:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: current
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- run: npm audit --omit=dev
|
||||
- run: npm audit --omit=dev
|
||||
|
||||
test:
|
||||
needs: [audit]
|
||||
runs-on: ubuntu-latest
|
||||
test:
|
||||
needs: [audit]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: ['14', '16', '18']
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: ["14", "16", "18"]
|
||||
|
||||
steps:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
steps:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- run: npm ci
|
||||
- run: npm ci
|
||||
|
||||
- name: Test
|
||||
run: npm test
|
||||
- name: Test
|
||||
run: npm test
|
||||
# - uses: actions/upload-artifact@v3
|
||||
# if: failure()
|
||||
# with:
|
||||
|
@ -1,7 +1 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"singleQuote": true,
|
||||
"quoteProps": "consistent",
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
{}
|
||||
|
244
CHANGELOG.md
244
CHANGELOG.md
@ -9,311 +9,311 @@ and this project adheres to [Semantic Versioning](https://semver.org).
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- Complete rewrite of the editor. API has changed significantly, please see the [migration guide](TBD).
|
||||
- Complete rewrite of the editor. API has changed significantly, please see the [migration guide](TBD).
|
||||
|
||||
## [2.18.0] - 2022-09-20
|
||||
|
||||
### Added
|
||||
|
||||
- `toolbarButtonClassPrefix` option to resolve conflicts with Bootstrap classes ([#493]).
|
||||
- `toolbarButtonClassPrefix` option to resolve conflicts with Bootstrap classes ([#493]).
|
||||
|
||||
## [2.17.0] - 2022-08-20
|
||||
|
||||
### Added
|
||||
|
||||
- Improved CSRF support for uploading images (Thanks to [@ZsgsDesign], [#394]).
|
||||
- Option to register an image preview handler: `imagesPreviewHandler` (Thanks to [@diego-gw], [#411]).
|
||||
- Support for `.webp` image formats (Thanks to [@sghoweri], [#417]).
|
||||
- `toggleHeading` methods for headings 4, 5 and 6 (Thanks to [@vanillajonathan], [#449] and [#492]).
|
||||
- Support for `.gif`, `.avif` and `.apng` image formats (Thanks to [@vanillajonathan], [#450], [#458] and [#459]).
|
||||
- Keyboard shortcuts for `toggleHeading` methods (Thanks to [@vanillajonathan], [#451]).
|
||||
- `iconClassMap` option to specify icon class names for toolbar buttons (Thanks to [@vanillajonathan], [#454]).
|
||||
- `role="toolbar"` on the toolbar element (Thanks to [@vanillajonathan], [#455]).
|
||||
- Support for text buttons in the toolbar (Thanks to [@vanillajonathan], [#461]).
|
||||
- `aria-label` attribute for toolbar buttons (uses the `title` option) (Thanks to [@vanillajonathan], [#463]).
|
||||
- `role="application"` on the editor container element (Thanks to [@vanillajonathan], [#464]).
|
||||
- Option to not overwrite the preview HTML by returning `null` from `previewRender` (Thanks to [@LevitatingOrange], [#471]).
|
||||
- Improved CSRF support for uploading images (Thanks to [@ZsgsDesign], [#394]).
|
||||
- Option to register an image preview handler: `imagesPreviewHandler` (Thanks to [@diego-gw], [#411]).
|
||||
- Support for `.webp` image formats (Thanks to [@sghoweri], [#417]).
|
||||
- `toggleHeading` methods for headings 4, 5 and 6 (Thanks to [@vanillajonathan], [#449] and [#492]).
|
||||
- Support for `.gif`, `.avif` and `.apng` image formats (Thanks to [@vanillajonathan], [#450], [#458] and [#459]).
|
||||
- Keyboard shortcuts for `toggleHeading` methods (Thanks to [@vanillajonathan], [#451]).
|
||||
- `iconClassMap` option to specify icon class names for toolbar buttons (Thanks to [@vanillajonathan], [#454]).
|
||||
- `role="toolbar"` on the toolbar element (Thanks to [@vanillajonathan], [#455]).
|
||||
- Support for text buttons in the toolbar (Thanks to [@vanillajonathan], [#461]).
|
||||
- `aria-label` attribute for toolbar buttons (uses the `title` option) (Thanks to [@vanillajonathan], [#463]).
|
||||
- `role="application"` on the editor container element (Thanks to [@vanillajonathan], [#464]).
|
||||
- Option to not overwrite the preview HTML by returning `null` from `previewRender` (Thanks to [@LevitatingOrange], [#471]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Hyperlink doubling (Thanks to [@danielok1993], [#95]).
|
||||
- URLs with certain characters entered through prompts causing invalid markdown (Thanks to [@Zignature], [#393]).
|
||||
- Autofocus option not working properly ([#399]).
|
||||
- Inconsistent border colour (Thanks to [@vanillajonathan], [#466]).
|
||||
- Invalid regex on Safari browsers ([#478])
|
||||
- `hideIcons` option type (Thanks to [@LoyalPotato], [#488]).
|
||||
- Hyperlink doubling (Thanks to [@danielok1993], [#95]).
|
||||
- URLs with certain characters entered through prompts causing invalid markdown (Thanks to [@Zignature], [#393]).
|
||||
- Autofocus option not working properly ([#399]).
|
||||
- Inconsistent border colour (Thanks to [@vanillajonathan], [#466]).
|
||||
- Invalid regex on Safari browsers ([#478])
|
||||
- `hideIcons` option type (Thanks to [@LoyalPotato], [#488]).
|
||||
|
||||
### Changed
|
||||
|
||||
- Editor now uses responsive font sizes (Thanks to [@vanillajonathan], [#452]).
|
||||
- Editor now uses responsive font sizes (Thanks to [@vanillajonathan], [#452]).
|
||||
|
||||
### Documentation
|
||||
|
||||
- Added several improvements to README (Thanks to [@vanillajonathan], [#436], [#438], [#440], [#444]).
|
||||
- Fixed typo in README (Thanks to [@kicksent], [#484]).
|
||||
- Added missing icon for `upload-image` in README (Thanks to [@hlf20010508], [#486]).
|
||||
- Added several improvements to README (Thanks to [@vanillajonathan], [#436], [#438], [#440], [#444]).
|
||||
- Fixed typo in README (Thanks to [@kicksent], [#484]).
|
||||
- Added missing icon for `upload-image` in README (Thanks to [@hlf20010508], [#486]).
|
||||
|
||||
## [2.16.1] - 2022-01-14
|
||||
|
||||
### Fixed
|
||||
|
||||
- Incorrect initial line and column count in status bar.
|
||||
- Security issue in `marked` dependency.
|
||||
- Incorrect initial line and column count in status bar.
|
||||
- Security issue in `marked` dependency.
|
||||
|
||||
## [2.16.0] - 2022-01-11
|
||||
|
||||
### Added
|
||||
|
||||
- `direction` option to enable RTL mode (Thanks to [@souljuse], [#358]).
|
||||
- `attributes` option to add custom attributes to toolbar buttons (Thanks to [@Zignature], [#388]).
|
||||
- `unorderedListStyle` option to change the character used for unordered lists (Thanks to [@Zignature], [#389]).
|
||||
- `direction` option to enable RTL mode (Thanks to [@souljuse], [#358]).
|
||||
- `attributes` option to add custom attributes to toolbar buttons (Thanks to [@Zignature], [#388]).
|
||||
- `unorderedListStyle` option to change the character used for unordered lists (Thanks to [@Zignature], [#389]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Image extension detection when extension is uppercase (Thanks to [@ukjinjang], [#357]).
|
||||
- Submenu actions not working in Chromium Browsers (Thanks to [@Offerel], [@robjean9] and [@kelvinj], [#364]).
|
||||
- Incorrect line and column count in status bar (Thanks to [@Zignature], [#384]).
|
||||
- Image extension detection when extension is uppercase (Thanks to [@ukjinjang], [#357]).
|
||||
- Submenu actions not working in Chromium Browsers (Thanks to [@Offerel], [@robjean9] and [@kelvinj], [#364]).
|
||||
- Incorrect line and column count in status bar (Thanks to [@Zignature], [#384]).
|
||||
|
||||
## [2.15.0] - 2021-04-22
|
||||
|
||||
### Added
|
||||
|
||||
- `imagePathAbsolute` option to return the absolute path when uploading an image (Thanks to [@wwsalmon], [#313]).
|
||||
- `imagePathAbsolute` option to return the absolute path when uploading an image (Thanks to [@wwsalmon], [#313]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- `ToolbarIcon` typings, added `icon` (Thanks to [@ChronosMasterOfAllTime], [#308]).
|
||||
- Image link extension when it was not the last part of the URL (Thanks to [@deerboy], [#311]).
|
||||
- Preview mode did not stay enabled when toggling to fullscreen (Thanks to [@smundro], [#316]).
|
||||
- Required typings not being included in `dependencies` (Thanks to [@marekdedic], [#322]).
|
||||
- `ToolbarIcon` typings, added `icon` (Thanks to [@ChronosMasterOfAllTime], [#308]).
|
||||
- Image link extension when it was not the last part of the URL (Thanks to [@deerboy], [#311]).
|
||||
- Preview mode did not stay enabled when toggling to fullscreen (Thanks to [@smundro], [#316]).
|
||||
- Required typings not being included in `dependencies` (Thanks to [@marekdedic], [#322]).
|
||||
|
||||
## [2.14.0] - 2021-02-14
|
||||
|
||||
### Added
|
||||
|
||||
- The `scrollbarStyle` option to change the style of the scrollbar (Thanks to [@danice], [#250]).
|
||||
- The `scrollbarStyle` option to change the style of the scrollbar (Thanks to [@danice], [#250]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Issues with images not displaying correctly in the preview screen (Thanks to [@ivictbor], [#253]).
|
||||
- An error when both `sideBySideFullscreen` and `status` were set to `false` (Thanks to [@joahim], [#272]).
|
||||
- Editor trying to display non-image files (Thanks to [@Juupaa], [#277])
|
||||
- Unneeded call to `window.removeEventListener` (Thanks to [@emirotin], [#280])
|
||||
- Spell checker (Thanks to [@Fanvadar], [#284]).
|
||||
- Focus issues with toolbar dropdown menus (Thanks to [@Situphen], [#285]).
|
||||
- Interaction between the `sideBySideFullscreen` and the preview state (Thanks to [@smundro], [#286])
|
||||
- Refactored strange method of padding the toolbar into regular padding (Thanks to [@sn3p], [#293]).
|
||||
- Security issue in `marked` dependency (Thanks to [@dependabot], [#298]).
|
||||
- Issues with images not displaying correctly in the preview screen (Thanks to [@ivictbor], [#253]).
|
||||
- An error when both `sideBySideFullscreen` and `status` were set to `false` (Thanks to [@joahim], [#272]).
|
||||
- Editor trying to display non-image files (Thanks to [@Juupaa], [#277])
|
||||
- Unneeded call to `window.removeEventListener` (Thanks to [@emirotin], [#280])
|
||||
- Spell checker (Thanks to [@Fanvadar], [#284]).
|
||||
- Focus issues with toolbar dropdown menus (Thanks to [@Situphen], [#285]).
|
||||
- Interaction between the `sideBySideFullscreen` and the preview state (Thanks to [@smundro], [#286])
|
||||
- Refactored strange method of padding the toolbar into regular padding (Thanks to [@sn3p], [#293]).
|
||||
- Security issue in `marked` dependency (Thanks to [@dependabot], [#298]).
|
||||
|
||||
## [2.13.0] - 2020-11-11
|
||||
|
||||
### Added
|
||||
|
||||
- CodeMirror autorefresh plugin and autoRefresh option (Thanks to [@mbolli], [#249]).
|
||||
- `lineNumbers` option to display line numbers in the editor (Thanks to [@nhymxu], [#267]).
|
||||
- CodeMirror autorefresh plugin and autoRefresh option (Thanks to [@mbolli], [#249]).
|
||||
- `lineNumbers` option to display line numbers in the editor (Thanks to [@nhymxu], [#267]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- CSS scoping issues when the editor is used in combination with other CodeMirror instances ([#252]).
|
||||
- CSS scoping issues when the editor is used in combination with other CodeMirror instances ([#252]).
|
||||
|
||||
## [2.12.1] - 2020-10-06
|
||||
|
||||
### Changed
|
||||
|
||||
- Set `previewImagesInEditor` option to `false` by default ([#251]).
|
||||
- Set `previewImagesInEditor` option to `false` by default ([#251]).
|
||||
|
||||
## [2.12.0] - 2020-09-29
|
||||
|
||||
### Added
|
||||
|
||||
- `this` context in imageUploadFunction (Thanks to [@JoshuaLicense], [#225]).
|
||||
- `previewImagesInEditor` option to display images in editor mode (Thanks to [@ivictbor], [#235]).
|
||||
- `overlayMode` options to supply an additional codemirror mode (Thanks to [@czynskee], [#244]).
|
||||
- `this` context in imageUploadFunction (Thanks to [@JoshuaLicense], [#225]).
|
||||
- `previewImagesInEditor` option to display images in editor mode (Thanks to [@ivictbor], [#235]).
|
||||
- `overlayMode` options to supply an additional codemirror mode (Thanks to [@czynskee], [#244]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Corrected default size units from `b,Kb,Mb` to ` B, KB, MB` ([#239]).
|
||||
- Max height less than min height (Thanks to [@nick-denry], [#222]).
|
||||
- toTextArea issue (Thanks to [@nick-denry], [#223]).
|
||||
- Error when updateStatusBar was called during image upload, but the status bar is disabled (Thanks to [@JoshuaLicense], [#224]).
|
||||
- Corrected default size units from `b,Kb,Mb` to ` B, KB, MB` ([#239]).
|
||||
- Max height less than min height (Thanks to [@nick-denry], [#222]).
|
||||
- toTextArea issue (Thanks to [@nick-denry], [#223]).
|
||||
- Error when updateStatusBar was called during image upload, but the status bar is disabled (Thanks to [@JoshuaLicense], [#224]).
|
||||
|
||||
## [2.11.0] - 2020-07-16
|
||||
|
||||
### Added
|
||||
|
||||
- Support for Node.js 14.
|
||||
- Preview without fullscreen (Thanks to [@nick-denry], [#196]).
|
||||
- Support for Node.js 14.
|
||||
- Preview without fullscreen (Thanks to [@nick-denry], [#196]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix cursor displayed position on activity (Thanks to [@firm1], [#184]).
|
||||
- Checkboxes always have bullets in front of them ([#136]).
|
||||
- Save the text only when modifying the content of the easymde instance (Thanks to [@firm1], [#181]).
|
||||
- Fix cursor displayed position on activity (Thanks to [@firm1], [#184]).
|
||||
- Checkboxes always have bullets in front of them ([#136]).
|
||||
- Save the text only when modifying the content of the easymde instance (Thanks to [@firm1], [#181]).
|
||||
|
||||
## [2.10.1] - 2020-04-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Typescript error when entering certain strings for toolbar buttons ([#178]).
|
||||
- Typescript error when entering certain strings for toolbar buttons ([#178]).
|
||||
|
||||
## [2.10.0] - 2020-04-02
|
||||
|
||||
### Added
|
||||
|
||||
- `inputStyle` and `nativeSpellcheck` options to manage the native language of the browser (Thanks to [@firm1], [#143]).
|
||||
- Group buttons in drop-down lists by adding a sub-option `children` for the items in the toolbar (Thanks to [@firm1], [#141]).
|
||||
- `sanitizerFunction` option to allow custom HTML sanitizing in the markdown preview (Thanks to [@adamb70], [#147]).
|
||||
- Time formatting and custom text options for the autosave message (Thanks to [@dima-bzz], [#170]).
|
||||
- `inputStyle` and `nativeSpellcheck` options to manage the native language of the browser (Thanks to [@firm1], [#143]).
|
||||
- Group buttons in drop-down lists by adding a sub-option `children` for the items in the toolbar (Thanks to [@firm1], [#141]).
|
||||
- `sanitizerFunction` option to allow custom HTML sanitizing in the markdown preview (Thanks to [@adamb70], [#147]).
|
||||
- Time formatting and custom text options for the autosave message (Thanks to [@dima-bzz], [#170]).
|
||||
|
||||
### Changed
|
||||
|
||||
- Delay before assuming that submit of the form as failed is `autosave.submit_delay` instead of `autosave.delay` (Thanks to [@Situphen], [#139]).
|
||||
- Add `watch` task for gulp (Thanks to [@A-312], [#150]).
|
||||
- Delay before assuming that submit of the form as failed is `autosave.submit_delay` instead of `autosave.delay` (Thanks to [@Situphen], [#139]).
|
||||
- Add `watch` task for gulp (Thanks to [@A-312], [#150]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Issue with Marked when using IE11 and webpack (Thanks to [@felipefdl], [#169]).
|
||||
- Updated codemirror to version 5.52.2 (Thanks to [@A-312], [#173]).
|
||||
- Editor displaying on top of other elements on a webpage (Thanks to [@StefKors], [#175]).
|
||||
- Issue with Marked when using IE11 and webpack (Thanks to [@felipefdl], [#169]).
|
||||
- Updated codemirror to version 5.52.2 (Thanks to [@A-312], [#173]).
|
||||
- Editor displaying on top of other elements on a webpage (Thanks to [@StefKors], [#175]).
|
||||
|
||||
## [2.9.0] - 2020-01-13
|
||||
|
||||
### Added
|
||||
|
||||
- Missing minHeight option in type definition (Thanks to [@t49tran], [#123]).
|
||||
- Other missing type definitions ([#126]).
|
||||
- Missing minHeight option in type definition (Thanks to [@t49tran], [#123]).
|
||||
- Other missing type definitions ([#126]).
|
||||
|
||||
### Changed
|
||||
|
||||
- The editor will remove its saved contents when the editor is emptied, allowing to reload a default value (Thanks to [@Situphen], [#132]).
|
||||
- The editor will remove its saved contents when the editor is emptied, allowing to reload a default value (Thanks to [@Situphen], [#132]).
|
||||
|
||||
## [2.8.0] - 2019-08-20
|
||||
|
||||
### Added
|
||||
|
||||
- Upload images functionality (Thanks to [@roipoussiere] and [@JeroenvO], [#71], [#101]).
|
||||
- Allow custom image upload function (Thanks to [@sperezp], [#106]).
|
||||
- More polish to the upload images functionality (Thanks to [@jfly], [#109]).
|
||||
- Improved React compatibility (Thanks to [@richtera], [#97]).
|
||||
- Upload images functionality (Thanks to [@roipoussiere] and [@JeroenvO], [#71], [#101]).
|
||||
- Allow custom image upload function (Thanks to [@sperezp], [#106]).
|
||||
- More polish to the upload images functionality (Thanks to [@jfly], [#109]).
|
||||
- Improved React compatibility (Thanks to [@richtera], [#97]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Missing link in dist file header.
|
||||
- Missing link in dist file header.
|
||||
|
||||
## [2.7.0] - 2019-07-13
|
||||
|
||||
### Added
|
||||
|
||||
- `previewClass` option for overwriting the preview screen class ([#99]).
|
||||
- `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.
|
||||
- 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]).
|
||||
- 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]).
|
||||
- Issue templates.
|
||||
- Standardized changelog file.
|
||||
- Contributing guide (Thanks to [@roipoussiere], [#54]).
|
||||
- Issue templates.
|
||||
- Standardized changelog file.
|
||||
|
||||
### Changed
|
||||
|
||||
- Finish rewrite of README (Thanks to [@roipoussiere], [#54]).
|
||||
- Image and link prompt fill with "https://" by default.
|
||||
- Link to markdown guide to <https://www.markdownguide.org/basic-syntax/>.
|
||||
- Finish rewrite of README (Thanks to [@roipoussiere], [#54]).
|
||||
- Image and link prompt fill with "https://" by default.
|
||||
- Link to markdown guide to <https://www.markdownguide.org/basic-syntax/>.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Backwards compatibility in the API with SimpleMDE 1.0.0 ([#41]).
|
||||
- Automatic publish of master branch to `@next`
|
||||
- Backwards compatibility in the API with SimpleMDE 1.0.0 ([#41]).
|
||||
- Automatic publish of master branch to `@next`
|
||||
|
||||
### Removed
|
||||
|
||||
- Distribution files from source-control.
|
||||
- Distribution files from source-control.
|
||||
|
||||
## [2.5.1] - 2019-01-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- `role="button"` needed to be `type="button"` ([#45]).
|
||||
- `role="button"` needed to be `type="button"` ([#45]).
|
||||
|
||||
## [2.5.0] - 2019-01-17
|
||||
|
||||
### Added
|
||||
|
||||
- Typescript support (Thanks to [@FranklinWhale], [#44]).
|
||||
- `role="button"` to toolbar buttons ([#38]).
|
||||
- Typescript support (Thanks to [@FranklinWhale], [#44]).
|
||||
- `role="button"` to toolbar buttons ([#38]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Eraser icon not working with FontAwesome 5.
|
||||
- Eraser icon not working with FontAwesome 5.
|
||||
|
||||
## [2.4.2] - 2018-11-09
|
||||
|
||||
### Added
|
||||
|
||||
- Node.js 11 support.
|
||||
- Node.js 11 support.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Header button icons not showing sub-icons with FontAwesome 5.
|
||||
- Inconsistent autosave behaviour when submitting a form (Thanks to [@Furgas] and [@adamb70], [#31]).
|
||||
- Header button icons not showing sub-icons with FontAwesome 5.
|
||||
- Inconsistent autosave behaviour when submitting a form (Thanks to [@Furgas] and [@adamb70], [#31]).
|
||||
|
||||
## [2.4.1] - 2018-10-15
|
||||
|
||||
### Added
|
||||
|
||||
- `fa-redo` class to redo button for FA5 compatibility (Thanks to [@Summon528], [#27]).
|
||||
- `fa-redo` class to redo button for FA5 compatibility (Thanks to [@Summon528], [#27]).
|
||||
|
||||
## [2.4.0] - 2018-10-15
|
||||
|
||||
### Added
|
||||
|
||||
- Theming support (Thanks to [@LeviticusMB], [#17]).
|
||||
- onToggleFullscreen event hook (Thanks to [@n-3-0], [#16]).
|
||||
- Theming support (Thanks to [@LeviticusMB], [#17]).
|
||||
- onToggleFullscreen event hook (Thanks to [@n-3-0], [#16]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fullscreen not working with `toolbar: false` (Thanks to [@aphitiel], [#19]).
|
||||
- Fullscreen not working with `toolbar: false` (Thanks to [@aphitiel], [#19]).
|
||||
|
||||
## [2.2.2] - 2019-07-03
|
||||
|
||||
### Fixed
|
||||
|
||||
- Automatic publish only publishing tags.
|
||||
- Automatic publish only publishing tags.
|
||||
|
||||
## [2.2.1] - 2019-06-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Attempt automatic publish `@next` version on npm.
|
||||
- Links in the preview window will open in a new tab by default.
|
||||
- Attempt automatic publish `@next` version on npm.
|
||||
- Links in the preview window will open in a new tab by default.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Multi-text select issue by disabling multi-select in the editor ([#10]).
|
||||
- `main` file in package.json (Thanks to [@sne11ius], [#11]).
|
||||
- Multi-text select issue by disabling multi-select in the editor ([#10]).
|
||||
- `main` file in package.json (Thanks to [@sne11ius], [#11]).
|
||||
|
||||
## [2.0.1] - 2018-05-13
|
||||
|
||||
### Changed
|
||||
|
||||
- Rewrote part of the documentation for EasyMDE.
|
||||
- Updated gulp to version 4.0.0.
|
||||
- Rewrote part of the documentation for EasyMDE.
|
||||
- Updated gulp to version 4.0.0.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Icons for `heading-smaller`, `heading-bigger`, `heading-1`, `heading-2` and `heading-3` not showing ([#9]).
|
||||
- Icons for `heading-smaller`, `heading-bigger`, `heading-1`, `heading-2` and `heading-3` not showing ([#9]).
|
||||
|
||||
## [2.0.0] - 2018-04-23
|
||||
|
||||
@ -321,23 +321,23 @@ Project forked from [SimpleMDE](https://github.com/sparksuite/simplemde-markdown
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- Dropped Bower support.
|
||||
- Dropped support for older Node.js versions.
|
||||
- Dropped Bower support.
|
||||
- Dropped support for older Node.js versions.
|
||||
|
||||
### Added
|
||||
|
||||
- FontAwesome 5 support.
|
||||
- Support for newer Node.js versions.
|
||||
- FontAwesome 5 support.
|
||||
- Support for newer Node.js versions.
|
||||
|
||||
### Changed
|
||||
|
||||
- Packages are now version-locked.
|
||||
- Simplified build script.
|
||||
- Markdown guide button is no longer disabled in preview mode.
|
||||
- Packages are now version-locked.
|
||||
- Simplified build script.
|
||||
- Markdown guide button is no longer disabled in preview mode.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Cursor not always showing in "text" mode over the edit field
|
||||
- Cursor not always showing in "text" mode over the edit field
|
||||
|
||||
<!-- Linked issues -->
|
||||
|
||||
|
36
README.md
36
README.md
@ -22,14 +22,14 @@ The editor is entirely customizable, from theming to toolbar buttons and javascr
|
||||
|
||||
## Quick access
|
||||
|
||||
- [EasyMDE - Markdown Editor](#easymde---markdown-editor)
|
||||
- [Quick access](#quick-access)
|
||||
- [Install EasyMDE](#install-easymde)
|
||||
- [How to use](#how-to-use)
|
||||
- [How it works](#how-it-works)
|
||||
- [SimpleMDE fork](#simplemde-fork)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
- [EasyMDE - Markdown Editor](#easymde---markdown-editor)
|
||||
- [Quick access](#quick-access)
|
||||
- [Install EasyMDE](#install-easymde)
|
||||
- [How to use](#how-to-use)
|
||||
- [How it works](#how-it-works)
|
||||
- [SimpleMDE fork](#simplemde-fork)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
## Install EasyMDE
|
||||
|
||||
@ -57,14 +57,14 @@ I originally made this fork to implement FontAwesome 5 compatibility into Simple
|
||||
|
||||
Changes include:
|
||||
|
||||
- FontAwesome 5 compatibility
|
||||
- Guide button works when editor is in preview mode
|
||||
- Links are now `https://` by default
|
||||
- Small styling changes
|
||||
- Support for Node 8 and beyond
|
||||
- Lots of refactored code
|
||||
- Links in preview will open in a new tab by default
|
||||
- TypeScript support
|
||||
- FontAwesome 5 compatibility
|
||||
- Guide button works when editor is in preview mode
|
||||
- Links are now `https://` by default
|
||||
- Small styling changes
|
||||
- Support for Node 8 and beyond
|
||||
- Lots of refactored code
|
||||
- Links in preview will open in a new tab by default
|
||||
- TypeScript support
|
||||
|
||||
My intention is to continue development on this project, improving it and keeping it alive.
|
||||
|
||||
@ -76,5 +76,5 @@ Want to contribute to EasyMDE? Thank you! We have a [contribution guide](./CONTR
|
||||
|
||||
This project is released under the [MIT License](./LICENSE).
|
||||
|
||||
- Copyright (c) 2015 Sparksuite, Inc.
|
||||
- Copyright (c) 2017 Jeroen Akkerman.
|
||||
- Copyright (c) 2015 Sparksuite, Inc.
|
||||
- Copyright (c) 2017 Jeroen Akkerman.
|
||||
|
82
eslint.config.js
Normal file
82
eslint.config.js
Normal file
@ -0,0 +1,82 @@
|
||||
// Core ESLint packages
|
||||
import eslint from "@eslint/js";
|
||||
import typescriptEslint from "typescript-eslint";
|
||||
|
||||
// Plugins
|
||||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
import eslintConfigUnicorn from "eslint-plugin-unicorn";
|
||||
import eslintPluginImport from "eslint-plugin-import";
|
||||
import eslintPluginSonarJS from "eslint-plugin-sonarjs";
|
||||
|
||||
export default typescriptEslint.config(
|
||||
{
|
||||
ignores: [
|
||||
"dist/**",
|
||||
"node_modules/**",
|
||||
"**/*.spec.ts",
|
||||
"**/*.test.ts",
|
||||
"vitest.config.ts",
|
||||
],
|
||||
},
|
||||
{
|
||||
files: ["**/*.ts"],
|
||||
extends: [
|
||||
eslint.configs.recommended,
|
||||
eslintPluginImport.flatConfigs.recommended,
|
||||
eslintPluginImport.flatConfigs.typescript,
|
||||
...typescriptEslint.configs.recommendedTypeChecked,
|
||||
...typescriptEslint.configs.stylisticTypeChecked,
|
||||
eslintPluginSonarJS.configs.recommended,
|
||||
eslintConfigUnicorn.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
|
||||
// Override specific rules for TypeScript files (these will take priority over the extended configs above)
|
||||
rules: {
|
||||
"unicorn/no-null": "off",
|
||||
"import/no-unresolved": "off",
|
||||
"unicorn/prefer-top-level-await": "off",
|
||||
"import/order": [
|
||||
"error",
|
||||
{
|
||||
alphabetize: {
|
||||
caseInsensitive: true,
|
||||
order: "asc",
|
||||
orderImportKind: "asc",
|
||||
},
|
||||
"newlines-between": "always",
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-namespace": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "error",
|
||||
"@typescript-eslint/no-misused-promises": [
|
||||
"error",
|
||||
{
|
||||
checksVoidReturn: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["**.*.spec.ts", "apps/client-e2e/**/*.ts"],
|
||||
rules: {
|
||||
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||
},
|
||||
},
|
||||
);
|
4424
package-lock.json
generated
4424
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
57
package.json
57
package.json
@ -27,43 +27,38 @@
|
||||
"test:unit": "vitest run",
|
||||
"test:e2e": "cypress run",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"format": "prettier --write . && eslint --fix ."
|
||||
"fix": "prettier --write . && eslint --fix ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/lang-markdown": "^6.2.5",
|
||||
"@codemirror/language": "^6.10.2",
|
||||
"@codemirror/state": "^6.4.1",
|
||||
"@codemirror/view": "^6.27.0",
|
||||
"@lezer/highlight": "^1.2.0",
|
||||
"@lezer/markdown": "^1.3.0",
|
||||
"@codemirror/lang-markdown": "^6.3.2",
|
||||
"@codemirror/language": "^6.11.0",
|
||||
"@codemirror/state": "^6.5.2",
|
||||
"@codemirror/view": "^6.36.6",
|
||||
"@lezer/highlight": "^1.2.1",
|
||||
"@lezer/markdown": "^1.4.3",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"marked": "^12.0.2"
|
||||
"marked": "^15.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionaru/eslint-config": "^9.2.1-53.0",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@eslint/js": "^9.25.1",
|
||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/node": "^20.14.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"@vitest/ui": "^1.6.0",
|
||||
"cypress": "^12.11.0",
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-prefer-arrow": "^1.2.3",
|
||||
"eslint-plugin-sonarjs": "^0.19.0",
|
||||
"eslint-plugin-unicorn": "^46.0.0",
|
||||
"jsdom": "^24.1.0",
|
||||
"prettier": "^3.3.1",
|
||||
"rollup": "^4.18.0",
|
||||
"@types/node": "^22.15.3",
|
||||
"@vitest/coverage-v8": "^3.1.2",
|
||||
"@vitest/ui": "^3.1.2",
|
||||
"cypress": "^14.3.2",
|
||||
"eslint": "^9.25.1",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-sonarjs": "^3.0.2",
|
||||
"eslint-plugin-unicorn": "^59.0.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"prettier": "^3.5.3",
|
||||
"rollup": "^4.40.1",
|
||||
"rollup-plugin-cleaner": "^1.0.0",
|
||||
"rollup-plugin-scss": "^4.0.0",
|
||||
"sass": "^1.77.4",
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.6.0"
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.31.1",
|
||||
"vitest": "^3.1.2"
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,28 @@
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
import cleaner from 'rollup-plugin-cleaner';
|
||||
import scss from 'rollup-plugin-scss';
|
||||
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
||||
import terser from "@rollup/plugin-terser";
|
||||
import typescript from "@rollup/plugin-typescript";
|
||||
import cleaner from "rollup-plugin-cleaner";
|
||||
import scss from "rollup-plugin-scss";
|
||||
|
||||
export default [
|
||||
// Browser configuration
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
input: "src/index.ts",
|
||||
output: {
|
||||
file: 'dist/browser/easymde.min.js',
|
||||
file: "dist/browser/easymde.min.js",
|
||||
inlineDynamicImports: true,
|
||||
sourcemap: true,
|
||||
},
|
||||
plugins: [
|
||||
cleaner({
|
||||
targets: ['./dist/'],
|
||||
targets: ["./dist/"],
|
||||
}),
|
||||
nodeResolve(),
|
||||
scss({
|
||||
fileName: 'easymde.css',
|
||||
fileName: "easymde.css",
|
||||
}),
|
||||
typescript(),
|
||||
terser(),
|
||||
],
|
||||
}
|
||||
},
|
||||
];
|
||||
|
@ -1,21 +1,20 @@
|
||||
/* eslint-disable sort-keys,@typescript-eslint/member-ordering */
|
||||
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
|
||||
import { markdown, markdownLanguage } from "@codemirror/lang-markdown";
|
||||
import {
|
||||
HighlightStyle,
|
||||
defaultHighlightStyle,
|
||||
syntaxHighlighting,
|
||||
} from '@codemirror/language';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { drawSelection, EditorView } from '@codemirror/view';
|
||||
import { tags } from '@lezer/highlight';
|
||||
import { marked } from 'marked';
|
||||
} from "@codemirror/language";
|
||||
import { EditorState } from "@codemirror/state";
|
||||
import { drawSelection, EditorView } from "@codemirror/view";
|
||||
import { tags } from "@lezer/highlight";
|
||||
import { marked } from "marked";
|
||||
|
||||
import { AlreadyConstructedError } from './errors/already-constructed-error';
|
||||
import { NotConstructedError } from './errors/not-constructed-error';
|
||||
import { importDefaultToolbar, importToolbar } from './imports';
|
||||
import { InputOptions, Options } from './options';
|
||||
import { AlreadyConstructedError } from "./errors/already-constructed-error";
|
||||
import { NotConstructedError } from "./errors/not-constructed-error";
|
||||
import { importDefaultToolbar, importToolbar } from "./imports";
|
||||
import { InputOptions, Options } from "./options";
|
||||
|
||||
import './styles.scss';
|
||||
import "./styles.scss";
|
||||
|
||||
export class EasyMDE {
|
||||
private readonly element: HTMLTextAreaElement;
|
||||
@ -30,15 +29,16 @@ export class EasyMDE {
|
||||
this.#options = {
|
||||
...options,
|
||||
blockStyles: {
|
||||
bold: '**',
|
||||
italic: '*',
|
||||
strikethrough: '~~',
|
||||
code: '`',
|
||||
bold: "**",
|
||||
italic: "*",
|
||||
strikethrough: "~~",
|
||||
code: "`",
|
||||
},
|
||||
};
|
||||
this.element = EasyMDE.verifyAndReturnElement(options.element);
|
||||
marked.parse('# EasyMDE');
|
||||
this.construct();
|
||||
marked.parse("# EasyMDE", { async: false });
|
||||
// eslint-disable-next-line sonarjs/no-async-constructor
|
||||
void this.construct();
|
||||
}
|
||||
|
||||
public get container(): HTMLDivElement {
|
||||
@ -84,45 +84,45 @@ export class EasyMDE {
|
||||
const highlightStyle = HighlightStyle.define([
|
||||
{
|
||||
tag: tags.heading1,
|
||||
fontSize: '200%',
|
||||
lineHeight: '200%',
|
||||
textDecoration: 'none',
|
||||
fontSize: "200%",
|
||||
lineHeight: "200%",
|
||||
textDecoration: "none",
|
||||
},
|
||||
{
|
||||
tag: tags.heading2,
|
||||
fontSize: '160%',
|
||||
lineHeight: '160%',
|
||||
textDecoration: 'none',
|
||||
fontSize: "160%",
|
||||
lineHeight: "160%",
|
||||
textDecoration: "none",
|
||||
},
|
||||
{
|
||||
tag: tags.heading3,
|
||||
fontSize: '125%',
|
||||
lineHeight: '125%',
|
||||
textDecoration: 'none',
|
||||
fontSize: "125%",
|
||||
lineHeight: "125%",
|
||||
textDecoration: "none",
|
||||
},
|
||||
{
|
||||
tag: tags.heading4,
|
||||
fontSize: '110%',
|
||||
lineHeight: '110%',
|
||||
textDecoration: 'none',
|
||||
fontSize: "110%",
|
||||
lineHeight: "110%",
|
||||
textDecoration: "none",
|
||||
},
|
||||
{
|
||||
tag: tags.heading5,
|
||||
fontSize: '105%',
|
||||
lineHeight: '105%',
|
||||
textDecoration: 'none',
|
||||
fontSize: "105%",
|
||||
lineHeight: "105%",
|
||||
textDecoration: "none",
|
||||
},
|
||||
{
|
||||
tag: tags.heading6,
|
||||
fontSize: '100%',
|
||||
lineHeight: '100%',
|
||||
textDecoration: 'none',
|
||||
fontSize: "100%",
|
||||
lineHeight: "100%",
|
||||
textDecoration: "none",
|
||||
},
|
||||
{
|
||||
tag: tags.monospace,
|
||||
fontFamily: 'monospace',
|
||||
textDecoration: 'none',
|
||||
background: 'rgba(0, 0, 0, 0.05)',
|
||||
fontFamily: "monospace",
|
||||
textDecoration: "none",
|
||||
background: "rgba(0, 0, 0, 0.05)",
|
||||
},
|
||||
]);
|
||||
|
||||
@ -158,7 +158,7 @@ export class EasyMDE {
|
||||
easyMDEContainer.append(await this.createStatusBar());
|
||||
}
|
||||
|
||||
this.element.insertAdjacentElement('afterend', easyMDEContainer);
|
||||
this.element.insertAdjacentElement("afterend", easyMDEContainer);
|
||||
|
||||
this.codemirror.focus();
|
||||
|
||||
@ -169,7 +169,7 @@ export class EasyMDE {
|
||||
this.element.value = this.codemirror.state.doc.toString();
|
||||
|
||||
for (const plugin of this.plugins) {
|
||||
plugin.destroy();
|
||||
void plugin.destroy();
|
||||
}
|
||||
|
||||
this.codemirror.destroy();
|
||||
@ -181,7 +181,7 @@ export class EasyMDE {
|
||||
this.element.hidden = false;
|
||||
}
|
||||
|
||||
public async addPlugin(plugin: IEasyMDEPlugin): Promise<IEasyMDEPlugin> {
|
||||
public addPlugin(plugin: IEasyMDEPlugin): IEasyMDEPlugin {
|
||||
this.plugins.push(plugin);
|
||||
return plugin;
|
||||
}
|
||||
@ -192,20 +192,20 @@ export class EasyMDE {
|
||||
importDefaultToolbar(),
|
||||
]);
|
||||
const toolbar = new Toolbar(this, defaultToolbar);
|
||||
await this.addPlugin(toolbar);
|
||||
this.addPlugin(toolbar);
|
||||
// await toolbar.build(defaultToolbar);
|
||||
return toolbar.element;
|
||||
}
|
||||
|
||||
private async createStatusBar(): Promise<HTMLDivElement> {
|
||||
const { StatusBar } = await import('./status-bar/status-bar');
|
||||
const { StatusBar } = await import("./status-bar/status-bar");
|
||||
const statusBar = new StatusBar(this);
|
||||
return statusBar.element;
|
||||
}
|
||||
|
||||
private createContainer(): HTMLDivElement {
|
||||
const container = document.createElement('div');
|
||||
container.classList.add('easymde-container');
|
||||
const container = document.createElement("div");
|
||||
container.classList.add("easymde-container");
|
||||
return container;
|
||||
}
|
||||
}
|
||||
@ -214,7 +214,7 @@ export type IEasyMDEPluginClass = new (easyMDE: EasyMDE) => IEasyMDEPlugin;
|
||||
|
||||
export interface IEasyMDEPlugin {
|
||||
// new (editor: EasyMDE, ...args: any): IEasyMDEPlugin;
|
||||
build(arguments_: any): Promise<void>;
|
||||
build(arguments_: unknown): Promise<void>;
|
||||
|
||||
destroy(): Promise<void>;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
export class AlreadyConstructedError extends Error {
|
||||
public constructor() {
|
||||
super('EasyMDE is already initialized.');
|
||||
this.name = 'AlreadyConstructedError';
|
||||
super("EasyMDE is already initialized.");
|
||||
this.name = "AlreadyConstructedError";
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,6 @@ export class NotConstructedError extends Error {
|
||||
super(
|
||||
'EasyMDE is not initialized, run the "construct()" method to do so.',
|
||||
);
|
||||
this.name = 'NotConstructedError';
|
||||
this.name = "NotConstructedError";
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
import { EasyMDE } from '../easymde';
|
||||
import { toggleBlock } from '../utils/toggle-block';
|
||||
|
||||
export const toggleBold = (editor: EasyMDE) =>
|
||||
toggleBlock(editor.codemirror, '**');
|
@ -1,5 +0,0 @@
|
||||
import { EasyMDE } from '../easymde';
|
||||
import { toggleBlock } from '../utils/toggle-block';
|
||||
|
||||
export const toggleItalic = (editor: EasyMDE) =>
|
||||
toggleBlock(editor.codemirror, '*');
|
@ -1,2 +1,2 @@
|
||||
export const importToolbar = () => import('./toolbar/toolbar');
|
||||
export const importDefaultToolbar = () => import('./toolbar/default-toolbar');
|
||||
export const importToolbar = () => import("./toolbar/toolbar");
|
||||
export const importDefaultToolbar = () => import("./toolbar/default-toolbar");
|
||||
|
21
src/index.ts
21
src/index.ts
@ -1,30 +1,29 @@
|
||||
export { EasyMDE } from './easymde';
|
||||
export * from './imports';
|
||||
export { EasyMDE } from "./easymde";
|
||||
export * from "./imports";
|
||||
|
||||
export class EasyMarkdownEditor extends HTMLElement {
|
||||
|
||||
name = 'World';
|
||||
name = "World";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.name = 'World';
|
||||
this.name = "World";
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
const shadow = this.attachShadow({ mode: 'closed' });
|
||||
shadow.innerHTML = 'Hello World!' + this.name;
|
||||
const shadow = this.attachShadow({ mode: "closed" });
|
||||
shadow.innerHTML = "Hello World!" + this.name;
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['name'];
|
||||
return ["name"];
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: string, oldValue: string, newValue: string) {
|
||||
if (name === 'name') {
|
||||
if (name === "name") {
|
||||
this.name = newValue;
|
||||
}
|
||||
console.log('Attribute Changed', name, oldValue, newValue);
|
||||
console.log("Attribute Changed", name, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define( 'easy-markdown-editor', EasyMarkdownEditor );
|
||||
customElements.define("easy-markdown-editor", EasyMarkdownEditor);
|
||||
|
@ -1,36 +1,36 @@
|
||||
import { MarkedOptions } from 'marked';
|
||||
import { MarkedOptions } from "marked";
|
||||
|
||||
import { EasyMDE } from './easymde';
|
||||
import { EasyMDE } from "./easymde";
|
||||
|
||||
interface ArrayOneOrMore<T> extends Array<T> {
|
||||
0: T;
|
||||
}
|
||||
|
||||
type ToolbarButton =
|
||||
| 'bold'
|
||||
| 'italic'
|
||||
| 'quote'
|
||||
| 'unordered-list'
|
||||
| 'ordered-list'
|
||||
| 'link'
|
||||
| 'image'
|
||||
| 'strikethrough'
|
||||
| 'code'
|
||||
| 'table'
|
||||
| 'redo'
|
||||
| 'heading'
|
||||
| 'undo'
|
||||
| 'heading-bigger'
|
||||
| 'heading-smaller'
|
||||
| 'heading-1'
|
||||
| 'heading-2'
|
||||
| 'heading-3'
|
||||
| 'clean-block'
|
||||
| 'horizontal-rule'
|
||||
| 'preview'
|
||||
| 'side-by-side'
|
||||
| 'fullscreen'
|
||||
| 'guide';
|
||||
| "bold"
|
||||
| "italic"
|
||||
| "quote"
|
||||
| "unordered-list"
|
||||
| "ordered-list"
|
||||
| "link"
|
||||
| "image"
|
||||
| "strikethrough"
|
||||
| "code"
|
||||
| "table"
|
||||
| "redo"
|
||||
| "heading"
|
||||
| "undo"
|
||||
| "heading-bigger"
|
||||
| "heading-smaller"
|
||||
| "heading-1"
|
||||
| "heading-2"
|
||||
| "heading-3"
|
||||
| "clean-block"
|
||||
| "horizontal-rule"
|
||||
| "preview"
|
||||
| "side-by-side"
|
||||
| "fullscreen"
|
||||
| "guide";
|
||||
|
||||
interface TimeFormatOptions {
|
||||
locale?: string | string[];
|
||||
@ -53,9 +53,7 @@ interface BlockStyleOptions {
|
||||
italic?: string;
|
||||
}
|
||||
|
||||
interface CustomAttributes {
|
||||
[key: string]: string;
|
||||
}
|
||||
type CustomAttributes = Record<string, string>;
|
||||
|
||||
interface InsertTextOptions {
|
||||
horizontalRule?: readonly string[];
|
||||
@ -77,6 +75,7 @@ interface PromptTexts {
|
||||
|
||||
interface RenderingOptions {
|
||||
codeSyntaxHighlighting?: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
hljs?: any;
|
||||
markedOptions?: MarkedOptions;
|
||||
sanitizerFunction?: (html: string) => string;
|
||||
@ -149,7 +148,7 @@ interface OverlayModeOptions {
|
||||
combine?: boolean;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
interface SpellCheckerOptions {
|
||||
// codeMirrorInstance: CodeMirror.Editor;
|
||||
}
|
||||
@ -183,22 +182,20 @@ export interface InputOptions {
|
||||
shortcuts?: Shortcuts;
|
||||
showIcons?: readonly ToolbarButton[];
|
||||
spellChecker?: boolean | ((options: SpellCheckerOptions) => void);
|
||||
inputStyle?: 'textarea' | 'contenteditable';
|
||||
inputStyle?: "textarea" | "contenteditable";
|
||||
nativeSpellcheck?: boolean;
|
||||
sideBySideFullscreen?: boolean;
|
||||
status?: boolean | ReadonlyArray<string | StatusBarItem>;
|
||||
status?: boolean | readonly (string | StatusBarItem)[];
|
||||
styleSelectedText?: boolean;
|
||||
tabSize?: number;
|
||||
toolbar?:
|
||||
| boolean
|
||||
| ReadonlyArray<
|
||||
'|' | ToolbarButton | ToolbarIcon | ToolbarDropdownIcon
|
||||
>;
|
||||
| readonly ("|" | ToolbarButton | ToolbarIcon | ToolbarDropdownIcon)[];
|
||||
toolbarTips?: boolean;
|
||||
onToggleFullScreen?: (goingIntoFullScreen: boolean) => void;
|
||||
theme?: string;
|
||||
scrollbarStyle?: string;
|
||||
unorderedListStyle?: '*' | '-' | '+';
|
||||
unorderedListStyle?: "*" | "-" | "+";
|
||||
|
||||
uploadImage?: boolean;
|
||||
imageMaxSize?: number;
|
||||
@ -220,16 +217,14 @@ export interface InputOptions {
|
||||
|
||||
overlayMode?: OverlayModeOptions;
|
||||
|
||||
direction?: 'ltr' | 'rtl';
|
||||
direction?: "ltr" | "rtl";
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
statusbar?: boolean;
|
||||
toolbar?:
|
||||
| boolean
|
||||
| ReadonlyArray<
|
||||
'|' | ToolbarButton | ToolbarIcon | ToolbarDropdownIcon
|
||||
>;
|
||||
| readonly ("|" | ToolbarButton | ToolbarIcon | ToolbarDropdownIcon)[];
|
||||
blockStyles: {
|
||||
bold: string;
|
||||
code: string;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { SelectionRange, StateEffect, Line } from '@codemirror/state';
|
||||
import { ViewPlugin, ViewUpdate } from '@codemirror/view';
|
||||
import { SelectionRange, StateEffect, Line } from "@codemirror/state";
|
||||
import { ViewPlugin, ViewUpdate } from "@codemirror/view";
|
||||
|
||||
import { EasyMDE } from '../easymde';
|
||||
import { countWords } from '../utils/count-words';
|
||||
import { EasyMDE } from "../easymde";
|
||||
import { countWords } from "../utils/count-words";
|
||||
|
||||
export class StatusBar {
|
||||
public element: HTMLDivElement;
|
||||
@ -17,8 +17,8 @@ export class StatusBar {
|
||||
private selectionEnd = 0;
|
||||
|
||||
public constructor(private editor: EasyMDE) {
|
||||
this.element = document.createElement('div');
|
||||
this.element.className = 'easymde-statusbar';
|
||||
this.element = document.createElement("div");
|
||||
this.element.className = "easymde-statusbar";
|
||||
|
||||
// Initial values
|
||||
this.characterCount = this.editor.codemirror.state.doc.length;
|
||||
@ -51,7 +51,7 @@ export class StatusBar {
|
||||
|
||||
let cursorLine: Line;
|
||||
|
||||
if (direction === 'left') {
|
||||
if (direction === "left") {
|
||||
// Cursor is at the start of the selection.
|
||||
cursorLine = fromLine;
|
||||
this.cursorColumn =
|
||||
@ -94,11 +94,12 @@ export class StatusBar {
|
||||
|
||||
private getSelectionDirection(
|
||||
selection: SelectionRange,
|
||||
): 'right' | 'left' | undefined {
|
||||
): "right" | "left" | undefined {
|
||||
return selection.from === this.selectionStart
|
||||
? 'right'
|
||||
: selection.to === this.selectionEnd
|
||||
? 'left'
|
||||
: undefined;
|
||||
? "right"
|
||||
: // eslint-disable-next-line sonarjs/no-nested-conditional
|
||||
selection.to === this.selectionEnd
|
||||
? "left"
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
import { ViewUpdate } from '@codemirror/view';
|
||||
|
||||
import { EasyMDE } from '../..';
|
||||
import { IToolbarButtonOptions } from '../default-toolbar';
|
||||
|
||||
export class ToolbarButton implements IToolbarButtonOptions {
|
||||
public action?: any;
|
||||
public active?:
|
||||
| boolean
|
||||
| ((editor: EasyMDE, update: ViewUpdate) => boolean)
|
||||
| ((editor: EasyMDE, update: ViewUpdate) => Promise<boolean>);
|
||||
public icon = '';
|
||||
public title = '';
|
||||
private _name = '';
|
||||
|
||||
public get name() {
|
||||
return this._name;
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import { ViewUpdate } from '@codemirror/view';
|
||||
import { ViewUpdate } from "@codemirror/view";
|
||||
|
||||
import { EasyMDE } from '../../easymde';
|
||||
import { checkBlock, toggleBlock } from '../../utils/toggle-block';
|
||||
import { IToolbarButtonOptions } from '../default-toolbar';
|
||||
import { EasyMDE } from "../../easymde";
|
||||
import { checkBlock, toggleBlock } from "../../utils/toggle-block";
|
||||
import { IToolbarButtonOptions } from "../default-toolbar";
|
||||
|
||||
export const toggleBold = (editor: EasyMDE) =>
|
||||
toggleBlock(editor.codemirror, editor.options.blockStyles.bold);
|
||||
@ -13,7 +13,7 @@ export const checkBold = (editor: EasyMDE, _update: ViewUpdate) =>
|
||||
export const toggleBoldButton: IToolbarButtonOptions = {
|
||||
action: toggleBold,
|
||||
active: checkBold,
|
||||
icon: 'fas fa-bold',
|
||||
name: 'bold',
|
||||
title: 'Bold',
|
||||
icon: "fas fa-bold",
|
||||
name: "bold",
|
||||
title: "Bold",
|
||||
};
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { EasyMDE } from '../../easymde';
|
||||
import { toggleBlock } from '../../utils/toggle-block';
|
||||
import { IToolbarButtonOptions } from '../default-toolbar';
|
||||
import { EasyMDE } from "../../easymde";
|
||||
import { toggleBlock } from "../../utils/toggle-block";
|
||||
import { IToolbarButtonOptions } from "../default-toolbar";
|
||||
|
||||
export const toggleCode = (editor: EasyMDE) =>
|
||||
toggleBlock(editor.codemirror, editor.options.blockStyles.code);
|
||||
|
||||
export const toggleCodeButton: IToolbarButtonOptions = {
|
||||
action: toggleCode,
|
||||
icon: 'fas fa-code',
|
||||
name: 'code',
|
||||
title: 'Code',
|
||||
icon: "fas fa-code",
|
||||
name: "code",
|
||||
title: "Code",
|
||||
};
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { ViewUpdate } from '@codemirror/view';
|
||||
import { ViewUpdate } from "@codemirror/view";
|
||||
|
||||
import { EasyMDE } from '../../easymde';
|
||||
import { checkBlock, toggleBlock } from '../../utils/toggle-block';
|
||||
import { IToolbarButtonOptions } from '../default-toolbar';
|
||||
import { EasyMDE } from "../../easymde";
|
||||
import { checkBlock, toggleBlock } from "../../utils/toggle-block";
|
||||
import { IToolbarButtonOptions } from "../default-toolbar";
|
||||
|
||||
export const toggleItalic = (editor: EasyMDE) =>
|
||||
toggleBlock(editor.codemirror, editor.options.blockStyles.italic);
|
||||
@ -13,7 +13,7 @@ export const checkItalic = (editor: EasyMDE, _update: ViewUpdate) =>
|
||||
export const toggleItalicButton: IToolbarButtonOptions = {
|
||||
action: toggleItalic,
|
||||
active: checkItalic,
|
||||
icon: 'fas fa-italic',
|
||||
name: 'italic',
|
||||
title: 'Italic',
|
||||
icon: "fas fa-italic",
|
||||
name: "italic",
|
||||
title: "Italic",
|
||||
};
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { EasyMDE } from '../../easymde';
|
||||
import { toggleBlock } from '../../utils/toggle-block';
|
||||
import { IToolbarButtonOptions } from '../default-toolbar';
|
||||
import { EasyMDE } from "../../easymde";
|
||||
import { toggleBlock } from "../../utils/toggle-block";
|
||||
import { IToolbarButtonOptions } from "../default-toolbar";
|
||||
|
||||
export const toggleStrikethrough = (editor: EasyMDE) =>
|
||||
toggleBlock(editor.codemirror, editor.options.blockStyles.strikethrough);
|
||||
|
||||
export const toggleStrikethroughButton: IToolbarButtonOptions = {
|
||||
action: toggleStrikethrough,
|
||||
icon: 'fas fa-strikethrough',
|
||||
name: 'strikethrough',
|
||||
title: 'Strikethrough',
|
||||
icon: "fas fa-strikethrough",
|
||||
name: "strikethrough",
|
||||
title: "Strikethrough",
|
||||
};
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { ViewUpdate } from '@codemirror/view';
|
||||
import { ViewUpdate } from "@codemirror/view";
|
||||
|
||||
import { EasyMDE } from '../easymde';
|
||||
import { EasyMDE } from "../easymde";
|
||||
|
||||
import { toggleBoldButton } from './buttons/toggle-bold';
|
||||
import { toggleCodeButton } from './buttons/toggle-code';
|
||||
import { toggleItalicButton } from './buttons/toggle-italic';
|
||||
// import { toggleStrikethroughButton } from "./buttons/toggle-strikethrough";
|
||||
import { toggleBoldButton } from "./buttons/toggle-bold";
|
||||
import { toggleCodeButton } from "./buttons/toggle-code";
|
||||
import { toggleItalicButton } from "./buttons/toggle-italic";
|
||||
import { toggleStrikethroughButton } from "./buttons/toggle-strikethrough";
|
||||
|
||||
export interface IToolbarButtonOptions {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
action?: any;
|
||||
active?:
|
||||
| boolean
|
||||
@ -22,53 +23,53 @@ export const defaultToolbar: IToolbarButtonOptions[][] = [
|
||||
[
|
||||
toggleBoldButton,
|
||||
toggleItalicButton,
|
||||
// toggleStrikethroughButton,
|
||||
toggleStrikethroughButton,
|
||||
{
|
||||
// action: toggleHeadingSmaller,
|
||||
icon: 'fas fa-header fa-heading',
|
||||
name: 'heading',
|
||||
title: 'Heading',
|
||||
icon: "fas fa-header fa-heading",
|
||||
name: "heading",
|
||||
title: "Heading",
|
||||
},
|
||||
],
|
||||
[
|
||||
toggleCodeButton,
|
||||
{
|
||||
// action: toggleBlockquote,
|
||||
icon: 'fas fa-quote-left',
|
||||
name: 'quote',
|
||||
title: 'Quote',
|
||||
icon: "fas fa-quote-left",
|
||||
name: "quote",
|
||||
title: "Quote",
|
||||
},
|
||||
{
|
||||
// action: toggleUnorderedList,
|
||||
icon: 'fas fa-list-ul',
|
||||
name: 'unordered-list',
|
||||
title: 'Generic List',
|
||||
icon: "fas fa-list-ul",
|
||||
name: "unordered-list",
|
||||
title: "Generic List",
|
||||
},
|
||||
{
|
||||
// action: toggleOrderedList,
|
||||
icon: 'fas fa-list-ol',
|
||||
name: 'ordered-list',
|
||||
title: 'Numbered List',
|
||||
icon: "fas fa-list-ol",
|
||||
name: "ordered-list",
|
||||
title: "Numbered List",
|
||||
},
|
||||
{
|
||||
// action: cleanBlock,
|
||||
icon: 'fas fa-eraser',
|
||||
name: 'clean-block',
|
||||
title: 'Clean block',
|
||||
icon: "fas fa-eraser",
|
||||
name: "clean-block",
|
||||
title: "Clean block",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
// action: drawLink,
|
||||
icon: 'fas fa-link',
|
||||
name: 'link',
|
||||
title: 'Create Link',
|
||||
icon: "fas fa-link",
|
||||
name: "link",
|
||||
title: "Create Link",
|
||||
},
|
||||
{
|
||||
// action: drawImage,
|
||||
icon: 'fas fa-image',
|
||||
name: 'image',
|
||||
title: 'Insert Image',
|
||||
icon: "fas fa-image",
|
||||
name: "image",
|
||||
title: "Insert Image",
|
||||
// }, {
|
||||
// // action: drawHorizontalRule,
|
||||
// icon: 'fas fa-minus',
|
||||
@ -99,11 +100,11 @@ export const defaultToolbar: IToolbarButtonOptions[][] = [
|
||||
],
|
||||
[
|
||||
{
|
||||
action: 'https://simplemde.com/markdown-guide',
|
||||
icon: 'fas fa-question',
|
||||
name: 'guide',
|
||||
action: "https://simplemde.com/markdown-guide",
|
||||
icon: "fas fa-question",
|
||||
name: "guide",
|
||||
// noDisable: true,
|
||||
title: 'Markdown Guide',
|
||||
title: "Markdown Guide",
|
||||
// }], [{
|
||||
// action: NewMDE.undo,
|
||||
// icon: 'fas fa-undo',
|
||||
|
@ -1,53 +0,0 @@
|
||||
import { EasyMDE } from '../easymde';
|
||||
|
||||
interface CustomAttributes {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
interface ArrayOneOrMore<T> extends Array<T> {
|
||||
0: T;
|
||||
}
|
||||
|
||||
interface ToolbarButtonOptions {
|
||||
name: string;
|
||||
action: string | ((editor: EasyMDE) => void);
|
||||
className: string;
|
||||
title: string;
|
||||
noDisable?: boolean;
|
||||
noMobile?: boolean;
|
||||
icon?: string;
|
||||
attributes?: CustomAttributes | undefined;
|
||||
}
|
||||
|
||||
interface ToolbarDropdownButtonOptions extends ToolbarButtonOptions {
|
||||
children: ArrayOneOrMore<ToolbarButtonOptions>;
|
||||
}
|
||||
|
||||
export class ToolbarButton {
|
||||
private readonly element = document.createElement('button');
|
||||
|
||||
public constructor(
|
||||
private options: ToolbarButtonOptions | ToolbarDropdownButtonOptions,
|
||||
) {
|
||||
this.setCustomAttributes();
|
||||
this.element.setAttribute('type', 'button');
|
||||
// Shortcuts
|
||||
// Tooltip
|
||||
if (options.noDisable) {
|
||||
// Disable on previes
|
||||
this.element.classList.add('no-disable');
|
||||
}
|
||||
if (options.noMobile) {
|
||||
// Hide on mobile
|
||||
this.element.classList.add('no-mobile');
|
||||
}
|
||||
this.element.tabIndex = -1;
|
||||
}
|
||||
|
||||
private setCustomAttributes(): void {
|
||||
const attributes = this.options.attributes || {};
|
||||
for (const [key, value] of Object.entries(attributes)) {
|
||||
this.element.setAttribute(key, value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
import { StateEffect } from '@codemirror/state';
|
||||
import { ViewPlugin, ViewUpdate } from '@codemirror/view';
|
||||
import { StateEffect } from "@codemirror/state";
|
||||
import { ViewPlugin, ViewUpdate } from "@codemirror/view";
|
||||
|
||||
import { EasyMDE, IEasyMDEPlugin } from '../easymde';
|
||||
import { EasyMDE, IEasyMDEPlugin } from "../easymde";
|
||||
|
||||
import { IToolbarButtonOptions } from './default-toolbar';
|
||||
import { IToolbarButtonOptions } from "./default-toolbar";
|
||||
|
||||
export class Toolbar implements IEasyMDEPlugin {
|
||||
private static readonly activeClass = 'enabled';
|
||||
private static readonly activeClass = "enabled";
|
||||
|
||||
public element: HTMLDivElement;
|
||||
|
||||
@ -14,12 +14,11 @@ export class Toolbar implements IEasyMDEPlugin {
|
||||
private editor: EasyMDE,
|
||||
toolbarLayout: IToolbarButtonOptions[][],
|
||||
) {
|
||||
this.element = document.createElement('div');
|
||||
this.element.className = 'easymde-toolbar';
|
||||
this.element = document.createElement("div");
|
||||
this.element.className = "easymde-toolbar";
|
||||
|
||||
for (const toolBarButtonSection of toolbarLayout) {
|
||||
const toolBarSection: Array<HTMLButtonElement | HTMLSpanElement> =
|
||||
[];
|
||||
const toolBarSection: (HTMLButtonElement | HTMLSpanElement)[] = [];
|
||||
|
||||
for (const toolBarButtonOptions of toolBarButtonSection) {
|
||||
toolBarSection.push(
|
||||
@ -52,10 +51,10 @@ export class Toolbar implements IEasyMDEPlugin {
|
||||
// return toolBar;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
public async build(toolbarLayout: IToolbarButtonOptions[][]) {
|
||||
for (const toolBarButtonSection of toolbarLayout) {
|
||||
const toolBarSection: Array<HTMLButtonElement | HTMLSpanElement> =
|
||||
[];
|
||||
const toolBarSection: (HTMLButtonElement | HTMLSpanElement)[] = [];
|
||||
|
||||
for (const toolBarButtonOptions of toolBarButtonSection) {
|
||||
toolBarSection.push(
|
||||
@ -76,14 +75,15 @@ export class Toolbar implements IEasyMDEPlugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
public async destroy() {
|
||||
this.element.remove();
|
||||
}
|
||||
|
||||
private createToolBarSeparator() {
|
||||
const separatorElement = document.createElement('span');
|
||||
separatorElement.className = 'separator';
|
||||
separatorElement.innerHTML = '|';
|
||||
const separatorElement = document.createElement("span");
|
||||
separatorElement.className = "separator";
|
||||
separatorElement.innerHTML = "|";
|
||||
return separatorElement;
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ export class Toolbar implements IEasyMDEPlugin {
|
||||
toolBarButtonOptions: IToolbarButtonOptions,
|
||||
): HTMLButtonElement {
|
||||
const buttonElement: HTMLButtonElement =
|
||||
document.createElement('button');
|
||||
document.createElement("button");
|
||||
buttonElement.tabIndex = -1;
|
||||
buttonElement.classList.add(toolBarButtonOptions.name);
|
||||
|
||||
@ -99,30 +99,32 @@ export class Toolbar implements IEasyMDEPlugin {
|
||||
buttonElement.title = toolBarButtonOptions.title;
|
||||
|
||||
// Set the button onclick action.
|
||||
if (typeof toolBarButtonOptions.action === 'function') {
|
||||
buttonElement.addEventListener('click', () =>
|
||||
if (typeof toolBarButtonOptions.action === "function") {
|
||||
buttonElement.addEventListener("click", () =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
|
||||
toolBarButtonOptions.action(this.editor),
|
||||
);
|
||||
// buttonElement.addEventListener()
|
||||
} else if (typeof toolBarButtonOptions.action === 'string') {
|
||||
buttonElement.addEventListener('click', () =>
|
||||
} else if (typeof toolBarButtonOptions.action === "string") {
|
||||
buttonElement.addEventListener("click", () =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
window.open(toolBarButtonOptions.action),
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof toolBarButtonOptions.active === 'boolean') {
|
||||
if (typeof toolBarButtonOptions.active === "boolean") {
|
||||
buttonElement.classList.toggle(
|
||||
Toolbar.activeClass,
|
||||
toolBarButtonOptions.active,
|
||||
);
|
||||
} else if (typeof toolBarButtonOptions.active === 'function') {
|
||||
} else if (typeof toolBarButtonOptions.active === "function") {
|
||||
this.editor.codemirror.dispatch({
|
||||
effects: StateEffect.appendConfig.of(
|
||||
ViewPlugin.define(() => ({
|
||||
update: async (update: ViewUpdate) => {
|
||||
if (
|
||||
typeof toolBarButtonOptions.active ===
|
||||
'function'
|
||||
"function"
|
||||
) {
|
||||
const result =
|
||||
await toolBarButtonOptions.active(
|
||||
@ -141,7 +143,7 @@ export class Toolbar implements IEasyMDEPlugin {
|
||||
}
|
||||
|
||||
// Set the button icon.
|
||||
const buttonIcon = document.createElement('i');
|
||||
const buttonIcon = document.createElement("i");
|
||||
buttonIcon.className = toolBarButtonOptions.icon;
|
||||
|
||||
buttonElement.append(buttonIcon);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Text } from '@codemirror/state';
|
||||
import { Text } from "@codemirror/state";
|
||||
|
||||
export const countWords = (document: Text) =>
|
||||
document
|
||||
@ -6,6 +6,6 @@ export const countWords = (document: Text) =>
|
||||
.reduce(
|
||||
(previous, current) =>
|
||||
previous +
|
||||
(current ? current.split(' ').filter(Boolean).length : 0),
|
||||
(current ? current.split(" ").filter(Boolean).length : 0),
|
||||
0,
|
||||
);
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { EditorView } from '@codemirror/view';
|
||||
import { markdown, markdownLanguage } from "@codemirror/lang-markdown";
|
||||
import { EditorState } from "@codemirror/state";
|
||||
import { EditorView } from "@codemirror/view";
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { checkBlock, toggleBlock } from './toggle-block';
|
||||
import { checkBlock, toggleBlock } from "./toggle-block";
|
||||
|
||||
const getEditor = (
|
||||
document: string,
|
||||
@ -22,8 +22,8 @@ const getEditor = (
|
||||
}),
|
||||
});
|
||||
|
||||
describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
'checkBlock simple %s',
|
||||
describe.each(["*", "**", "`", "_", "__", "~~"])(
|
||||
"checkBlock simple %s",
|
||||
(character) => {
|
||||
const wordSimple = `${character}foo${character}`;
|
||||
const wordSimpleWithSpace = `${character} foo ${character}`;
|
||||
@ -33,7 +33,7 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
const wordMultiLine = `${character}foo${character}\n${character}boo${character}`;
|
||||
const wordMultiTab = `${character}foo${character}\t${character}boo${character}`;
|
||||
|
||||
it('must detect an active block with selection point in the middle', () => {
|
||||
it("must detect an active block with selection point in the middle", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const anchor = Math.floor(wordSimple.length / 2);
|
||||
@ -44,7 +44,7 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it('must detect an active block with selection point in the middle of a word', () => {
|
||||
it("must detect an active block with selection point in the middle of a word", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const anchor = Math.floor(wordSquished.length / 2);
|
||||
@ -55,7 +55,7 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it('must not detect an active block with selection point in the middle of a word surrounded by spaces', () => {
|
||||
it("must not detect an active block with selection point in the middle of a word surrounded by spaces", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const anchor = Math.floor(wordSimpleWithSpace.length / 2);
|
||||
@ -66,14 +66,14 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it('must detect an active block with selection point at the start', () => {
|
||||
it("must detect an active block with selection point at the start", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const result = checkBlock(getEditor(wordSimple), character);
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it('must detect an active block with selection point at the end', () => {
|
||||
it("must detect an active block with selection point at the end", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const anchor = wordSimple.length;
|
||||
@ -84,7 +84,7 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it('must detect an active block with partial selection range in the middle', () => {
|
||||
it("must detect an active block with partial selection range in the middle", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const anchor = Math.floor(wordSimple.length / 2);
|
||||
@ -96,7 +96,7 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it('must detect an active block with selection range of the full word', () => {
|
||||
it("must detect an active block with selection range of the full word", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const anchor = character.length;
|
||||
@ -108,7 +108,7 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it('must detect an active block with selection range of the full text', () => {
|
||||
it("must detect an active block with selection range of the full text", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const head = wordSimple.length;
|
||||
@ -119,22 +119,22 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it('must detect an active block with selection on the first of multiple lines', () => {
|
||||
it("must detect an active block with selection on the first of multiple lines", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const anchor = Math.floor(wordMultiLine.split('\n')[0].length / 2);
|
||||
const anchor = Math.floor(wordMultiLine.split("\n")[0].length / 2);
|
||||
const result = checkBlock(
|
||||
getEditor(wordMultiLine, { anchor }),
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('foo');
|
||||
expect(result[1]).toBe("foo");
|
||||
});
|
||||
|
||||
it('must detect an active block with selection on the second of multiple lines', () => {
|
||||
it("must detect an active block with selection on the second of multiple lines", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const multiLineSplit = wordMultiLine.split('\n');
|
||||
const multiLineSplit = wordMultiLine.split("\n");
|
||||
const anchor =
|
||||
Math.floor(multiLineSplit[1].length / 2) +
|
||||
multiLineSplit[0].length;
|
||||
@ -143,10 +143,10 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('boo');
|
||||
expect(result[1]).toBe("boo");
|
||||
});
|
||||
|
||||
it('must detect an active block with selection at the end of multiple lines', () => {
|
||||
it("must detect an active block with selection at the end of multiple lines", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const anchor = wordMultiLine.length;
|
||||
@ -155,25 +155,25 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('boo');
|
||||
expect(result[1]).toBe("boo");
|
||||
});
|
||||
|
||||
it('must detect an active block with selection on the first of multiple words', () => {
|
||||
it("must detect an active block with selection on the first of multiple words", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const anchor = Math.floor(wordMultiWord.split(' ')[0].length / 2);
|
||||
const anchor = Math.floor(wordMultiWord.split(" ")[0].length / 2);
|
||||
const result = checkBlock(
|
||||
getEditor(wordMultiWord, { anchor }),
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('foo');
|
||||
expect(result[1]).toBe("foo");
|
||||
});
|
||||
|
||||
it('must detect an active block with selection on the second of multiple words', () => {
|
||||
it("must detect an active block with selection on the second of multiple words", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const multiWordSplit = wordMultiWord.split(' ');
|
||||
const multiWordSplit = wordMultiWord.split(" ");
|
||||
const anchor =
|
||||
Math.floor(multiWordSplit[1].length / 2) +
|
||||
multiWordSplit[0].length;
|
||||
@ -182,10 +182,10 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('boo');
|
||||
expect(result[1]).toBe("boo");
|
||||
});
|
||||
|
||||
it('must detect an active block with selection at the end of multiple words', () => {
|
||||
it("must detect an active block with selection at the end of multiple words", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const anchor = wordMultiWord.length;
|
||||
@ -194,25 +194,25 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('boo');
|
||||
expect(result[1]).toBe("boo");
|
||||
});
|
||||
|
||||
it('must detect an active block with selection on the first of multiple words separated by tab', () => {
|
||||
it("must detect an active block with selection on the first of multiple words separated by tab", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const anchor = Math.floor(wordMultiTab.split('\t')[0].length / 2);
|
||||
const anchor = Math.floor(wordMultiTab.split("\t")[0].length / 2);
|
||||
const result = checkBlock(
|
||||
getEditor(wordMultiTab, { anchor }),
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('foo');
|
||||
expect(result[1]).toBe("foo");
|
||||
});
|
||||
|
||||
it('must detect an active block with selection on the second of multiple words separated by tab', () => {
|
||||
it("must detect an active block with selection on the second of multiple words separated by tab", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const multiWordSplit = wordMultiTab.split('\t');
|
||||
const multiWordSplit = wordMultiTab.split("\t");
|
||||
const anchor =
|
||||
Math.floor(multiWordSplit[1].length / 2) +
|
||||
multiWordSplit[0].length;
|
||||
@ -221,10 +221,10 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('boo');
|
||||
expect(result[1]).toBe("boo");
|
||||
});
|
||||
|
||||
it('must detect an active block with selection at the end of multiple words separated by tab', () => {
|
||||
it("must detect an active block with selection at the end of multiple words separated by tab", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const anchor = wordMultiTab.length;
|
||||
@ -233,25 +233,25 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('boo');
|
||||
expect(result[1]).toBe("boo");
|
||||
});
|
||||
|
||||
it('must detect an active block with selection on the first of a multi-word text', () => {
|
||||
it("must detect an active block with selection on the first of a multi-word text", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const anchor = Math.floor(wordMultiWords.split(' ')[0].length / 2);
|
||||
const anchor = Math.floor(wordMultiWords.split(" ")[0].length / 2);
|
||||
const result = checkBlock(
|
||||
getEditor(wordMultiWords, { anchor }),
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('foo boo');
|
||||
expect(result[1]).toBe("foo boo");
|
||||
});
|
||||
|
||||
it('must detect an active block with selection on the second of a multi-word text', () => {
|
||||
it("must detect an active block with selection on the second of a multi-word text", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const multiWordSplit = wordMultiWords.split(' ');
|
||||
const multiWordSplit = wordMultiWords.split(" ");
|
||||
const anchor =
|
||||
Math.floor(multiWordSplit[1].length / 2) +
|
||||
multiWordSplit[0].length;
|
||||
@ -260,168 +260,168 @@ describe.each(['*', '**', '`', '_', '__', '~~'])(
|
||||
character,
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('foo boo');
|
||||
expect(result[1]).toBe("foo boo");
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
describe('checkBlock special cases', () => {
|
||||
it('must not detect an active block when another markdown block is used with more of the same characters', () => {
|
||||
describe("checkBlock special cases", () => {
|
||||
it("must not detect an active block when another markdown block is used with more of the same characters", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const result = checkBlock(getEditor('**foo**', { anchor: 4 }), '*');
|
||||
const result = checkBlock(getEditor("**foo**", { anchor: 4 }), "*");
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it('must not detect an active block when another markdown block is used with more of the same characters in a bigger context', () => {
|
||||
it("must not detect an active block when another markdown block is used with more of the same characters in a bigger context", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const result = checkBlock(
|
||||
getEditor('Some text **foo** more text', { anchor: 14 }),
|
||||
'*',
|
||||
getEditor("Some text **foo** more text", { anchor: 14 }),
|
||||
"*",
|
||||
);
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it('must detect an active block in a bigger context', () => {
|
||||
it("must detect an active block in a bigger context", () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const result = checkBlock(
|
||||
getEditor('Some text **foo** more text', { anchor: 14 }),
|
||||
'**',
|
||||
getEditor("Some text **foo** more text", { anchor: 14 }),
|
||||
"**",
|
||||
);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result[1]).toBe('foo');
|
||||
expect(result[1]).toBe("foo");
|
||||
});
|
||||
|
||||
it('must detect an active block when another markdown block is used with different characters', () => {
|
||||
it("must detect an active block when another markdown block is used with different characters", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const result = checkBlock(getEditor('__*foo*__', { anchor: 6 }), '*');
|
||||
const result = checkBlock(getEditor("__*foo*__", { anchor: 6 }), "*");
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it('must not detect an active block when another markdown block is used with less of the same characters', () => {
|
||||
it("must not detect an active block when another markdown block is used with less of the same characters", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const result = checkBlock(getEditor('*foo*', { anchor: 3 }), '**');
|
||||
const result = checkBlock(getEditor("*foo*", { anchor: 3 }), "**");
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it.each(['*', '**'])(
|
||||
'must detect an active block when the characters are part of another styling block',
|
||||
it.each(["*", "**"])(
|
||||
"must detect an active block when the characters are part of another styling block",
|
||||
(c) => {
|
||||
expect.assertions(1);
|
||||
|
||||
const result = checkBlock(getEditor('***foo***', { anchor: 5 }), c);
|
||||
const result = checkBlock(getEditor("***foo***", { anchor: 5 }), c);
|
||||
expect(result).toBeTruthy();
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe.skip('toggleBlock', () => {
|
||||
it('must toggle a single word on with the selection at the start', () => {
|
||||
describe.skip("toggleBlock", () => {
|
||||
it("must toggle a single word on with the selection at the start", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('Word', { anchor: 0 });
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('*Word*');
|
||||
const editor = getEditor("Word", { anchor: 0 });
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("*Word*");
|
||||
});
|
||||
|
||||
it('must toggle a single word on with the selection in the middle', () => {
|
||||
it("must toggle a single word on with the selection in the middle", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('Word', { anchor: 2 });
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('*Word*');
|
||||
const editor = getEditor("Word", { anchor: 2 });
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("*Word*");
|
||||
});
|
||||
|
||||
it('must toggle a single word on with the selection at the end', () => {
|
||||
it("must toggle a single word on with the selection at the end", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('Word', { anchor: 4 });
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('*Word*');
|
||||
const editor = getEditor("Word", { anchor: 4 });
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("*Word*");
|
||||
});
|
||||
|
||||
it('must toggle a single word on in between other words', () => {
|
||||
it("must toggle a single word on in between other words", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('Many words are typed here', { anchor: 7 });
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('Many *words* are typed here');
|
||||
const editor = getEditor("Many words are typed here", { anchor: 7 });
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("Many *words* are typed here");
|
||||
});
|
||||
|
||||
it('must toggle a single word on in between other words big selection', () => {
|
||||
it("must toggle a single word on in between other words big selection", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('Many words are typed here', {
|
||||
const editor = getEditor("Many words are typed here", {
|
||||
anchor: 5,
|
||||
head: 10,
|
||||
});
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('Many *words* are typed here');
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("Many *words* are typed here");
|
||||
});
|
||||
|
||||
it('must toggle a single word off with the selection at the start', () => {
|
||||
it("must toggle a single word off with the selection at the start", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('*Word*', { anchor: 0 });
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('Word');
|
||||
const editor = getEditor("*Word*", { anchor: 0 });
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("Word");
|
||||
});
|
||||
|
||||
it('must toggle a single word off with the selection in the middle', () => {
|
||||
it("must toggle a single word off with the selection in the middle", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('*Word*', { anchor: 3 });
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('Word');
|
||||
const editor = getEditor("*Word*", { anchor: 3 });
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("Word");
|
||||
});
|
||||
|
||||
it('must toggle a single word off with the selection at the end', () => {
|
||||
it("must toggle a single word off with the selection at the end", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('*Word*', { anchor: 6 });
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('Word');
|
||||
const editor = getEditor("*Word*", { anchor: 6 });
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("Word");
|
||||
});
|
||||
|
||||
it('must toggle a single word off in between other words', () => {
|
||||
it("must toggle a single word off in between other words", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('Many *words* are typed here', { anchor: 8 });
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('Many words are typed here');
|
||||
const editor = getEditor("Many *words* are typed here", { anchor: 8 });
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("Many words are typed here");
|
||||
});
|
||||
|
||||
it('must toggle a single word off in between other words big selection', () => {
|
||||
it("must toggle a single word off in between other words big selection", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('Many *words* are typed here', {
|
||||
const editor = getEditor("Many *words* are typed here", {
|
||||
anchor: 6,
|
||||
head: 11,
|
||||
});
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('Many words are typed here');
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("Many words are typed here");
|
||||
});
|
||||
|
||||
it('must toggle a formatted sentence off', () => {
|
||||
it("must toggle a formatted sentence off", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('*Many words are typed here*', { anchor: 8 });
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('Many words are typed here');
|
||||
const editor = getEditor("*Many words are typed here*", { anchor: 8 });
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("Many words are typed here");
|
||||
});
|
||||
|
||||
it('must toggle a formatted sentence off in a big selection', () => {
|
||||
it("must toggle a formatted sentence off in a big selection", () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const editor = getEditor('*Many words are typed here*', {
|
||||
const editor = getEditor("*Many words are typed here*", {
|
||||
anchor: 6,
|
||||
head: 11,
|
||||
});
|
||||
toggleBlock(editor, '*');
|
||||
expect(editor.state.doc.toString()).toBe('Many words are typed here');
|
||||
toggleBlock(editor, "*");
|
||||
expect(editor.state.doc.toString()).toBe("Many words are typed here");
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { EditorSelection, EditorState } from '@codemirror/state';
|
||||
import { EditorView } from '@codemirror/view';
|
||||
import escapeStringRegexp from 'escape-string-regexp';
|
||||
import { EditorSelection, EditorState } from "@codemirror/state";
|
||||
import { EditorView } from "@codemirror/view";
|
||||
import escapeStringRegexp from "escape-string-regexp";
|
||||
|
||||
/**
|
||||
* Checks whether the selection matches a formatted block of text.
|
||||
@ -18,7 +18,7 @@ export const checkBlock = (
|
||||
const escapedCharacters = escapeStringRegexp(characters);
|
||||
const regularExpression = new RegExp(
|
||||
`^${escapedCharacters}(.*)${escapedCharacters}$`,
|
||||
'gs',
|
||||
"gs",
|
||||
);
|
||||
|
||||
const checkResult = regularExpression.exec(text);
|
||||
@ -26,8 +26,16 @@ export const checkBlock = (
|
||||
let doubleCharactersCheckResult = null;
|
||||
let tripleCharactersCheckResult = null;
|
||||
if (characters.length === 1) {
|
||||
doubleCharactersCheckResult = checkBlock(editor, characters.repeat(2), minimal);
|
||||
tripleCharactersCheckResult = checkBlock(editor, characters.repeat(3), minimal);
|
||||
doubleCharactersCheckResult = checkBlock(
|
||||
editor,
|
||||
characters.repeat(2),
|
||||
minimal,
|
||||
);
|
||||
tripleCharactersCheckResult = checkBlock(
|
||||
editor,
|
||||
characters.repeat(3),
|
||||
minimal,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
@ -100,13 +108,14 @@ export const getExpandedSelection = (
|
||||
while (fromPosition >= 0) {
|
||||
const newText = state.sliceDoc(fromPosition, to);
|
||||
|
||||
if (newText.startsWith('\n') || newText.startsWith('\t')) {
|
||||
if (newText.startsWith("\n") || newText.startsWith("\t")) {
|
||||
fromPosition++;
|
||||
break;
|
||||
} else if (minimal && newText.startsWith(' ')) {
|
||||
// eslint-disable-next-line sonarjs/no-duplicated-branches
|
||||
} else if (minimal && newText.startsWith(" ")) {
|
||||
fromPosition++;
|
||||
break;
|
||||
} else if (newText.startsWith(characters + ' ')) {
|
||||
} else if (newText.startsWith(characters + " ")) {
|
||||
fromPosition += characters.length + 1;
|
||||
break;
|
||||
} else if (
|
||||
@ -123,10 +132,11 @@ export const getExpandedSelection = (
|
||||
let toPosition = to;
|
||||
while (toPosition < state.doc.length) {
|
||||
const newText = state.sliceDoc(from, toPosition);
|
||||
if (newText.endsWith('\n') || newText.endsWith('\t')) {
|
||||
if (newText.endsWith("\n") || newText.endsWith("\t")) {
|
||||
toPosition--;
|
||||
break;
|
||||
} else if (minimal && newText.endsWith(' ')) {
|
||||
// eslint-disable-next-line sonarjs/no-duplicated-branches
|
||||
} else if (minimal && newText.endsWith(" ")) {
|
||||
toPosition--;
|
||||
break;
|
||||
} else if (
|
||||
|
@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
@ -57,9 +57,9 @@ This is a longer sentence!
|
||||
EasyMDE,
|
||||
importToolbar,
|
||||
importDefaultToolbar,
|
||||
} from '../dist/browser/easymde.min.js';
|
||||
} from "../dist/browser/easymde.min.js";
|
||||
window.x = new EasyMDE({
|
||||
element: document.getElementById('my-text-area'),
|
||||
element: document.getElementById("my-text-area"),
|
||||
toolbar: true,
|
||||
statusbar: true,
|
||||
});
|
||||
@ -71,9 +71,11 @@ This is a longer sentence!
|
||||
// window.x.destruct();
|
||||
</script>
|
||||
|
||||
<easy-markdown-editor name="meow"></easy-markdown-editor>
|
||||
<script>
|
||||
document.querySelector('easy-markdown-editor').setAttribute('name', 'Everyone');
|
||||
</script>
|
||||
<easy-markdown-editor name="meow"></easy-markdown-editor>
|
||||
<script>
|
||||
document
|
||||
.querySelector("easy-markdown-editor")
|
||||
.setAttribute("name", "Everyone");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
@ -36,7 +36,7 @@ const x = "moooo";
|
||||
>
|
||||
<script type="module">
|
||||
window.x = new EasyMDE({
|
||||
element: document.getElementById('text'),
|
||||
element: document.getElementById("text"),
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
@ -6,11 +6,11 @@ export default defineConfig({
|
||||
all: true,
|
||||
clean: true,
|
||||
enabled: true,
|
||||
include: ['src/**/*.ts'],
|
||||
provider: 'v8',
|
||||
include: ["src/**/*.ts"],
|
||||
provider: "v8",
|
||||
},
|
||||
dir: 'src',
|
||||
environment: 'jsdom',
|
||||
include: ['**/*.spec.ts'],
|
||||
dir: "src",
|
||||
environment: "jsdom",
|
||||
include: ["**/*.spec.ts"],
|
||||
},
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user