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