neiki-editor 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/neiki-editor.css +1 -1
- package/dist/neiki-editor.js +93 -8
- package/dist/neiki-editor.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<img src="https://img.shields.io/badge/web%20components-29ABE2.svg?style=for-the-badge&logo=webcomponentsdotorg&logoColor=white" alt="Web Components">
|
|
12
12
|
<br>
|
|
13
13
|
<img src="https://img.shields.io/badge/License-AGPL--3.0-2563EB?style=for-the-badge&logo=open-source-initiative&logoColor=white&labelColor=000F15&logoWidth=20" alt="License">
|
|
14
|
-
<img src="https://img.shields.io/badge/Version-3.
|
|
14
|
+
<img src="https://img.shields.io/badge/Version-3.6.0-2563EB?style=for-the-badge&logo=semantic-release&logoColor=white&labelColor=000F15&logoWidth=20" alt="Version">
|
|
15
15
|
</p>
|
|
16
16
|
|
|
17
17
|
<p align="center">
|
|
@@ -140,7 +140,7 @@ The recommended install is the single bundled script from the CDN. CSS is includ
|
|
|
140
140
|
**Pin a specific version**
|
|
141
141
|
|
|
142
142
|
```html
|
|
143
|
-
<script src="https://cdn.neikiri.dev/neiki-editor/3.
|
|
143
|
+
<script src="https://cdn.neikiri.dev/neiki-editor/3.6.0/neiki-editor.min.js"></script>
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
**Load CSS and JS separately**
|
|
@@ -151,8 +151,8 @@ The recommended install is the single bundled script from the CDN. CSS is includ
|
|
|
151
151
|
<script src="https://cdn.neikiri.dev/neiki-editor/neiki-editor.js"></script>
|
|
152
152
|
|
|
153
153
|
<!-- Or pinned -->
|
|
154
|
-
<link rel="stylesheet" href="https://cdn.neikiri.dev/neiki-editor/3.
|
|
155
|
-
<script src="https://cdn.neikiri.dev/neiki-editor/3.
|
|
154
|
+
<link rel="stylesheet" href="https://cdn.neikiri.dev/neiki-editor/3.6.0/neiki-editor.css">
|
|
155
|
+
<script src="https://cdn.neikiri.dev/neiki-editor/3.6.0/neiki-editor.js"></script>
|
|
156
156
|
```
|
|
157
157
|
|
|
158
158
|
**Alternative CDN — jsDelivr**
|
|
@@ -160,7 +160,7 @@ The recommended install is the single bundled script from the CDN. CSS is includ
|
|
|
160
160
|
```html
|
|
161
161
|
<script src="https://cdn.jsdelivr.net/gh/neikiri/neiki-editor@latest/dist/neiki-editor.min.js"></script>
|
|
162
162
|
<!-- Pinned -->
|
|
163
|
-
<script src="https://cdn.jsdelivr.net/gh/neikiri/neiki-editor@3.
|
|
163
|
+
<script src="https://cdn.jsdelivr.net/gh/neikiri/neiki-editor@3.6.0/dist/neiki-editor.min.js"></script>
|
|
164
164
|
```
|
|
165
165
|
|
|
166
166
|
**Package manager**
|
package/dist/neiki-editor.css
CHANGED
package/dist/neiki-editor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NeikiEditor - A Modern WYSIWYG Editor
|
|
3
|
-
* Version: 3.
|
|
3
|
+
* Version: 3.6.0
|
|
4
4
|
*
|
|
5
5
|
* A lightweight, feature-rich text editor with support for:
|
|
6
6
|
* - Rich text formatting (bold, italic, underline, etc.)
|
|
@@ -3114,7 +3114,7 @@
|
|
|
3114
3114
|
<img src="https://github.com/neikiri/neiki-editor/raw/main/assets/logo.svg" alt="Neiki's Editor" style="width: 240px; height: auto; margin: 0 auto 16px; display: block;">
|
|
3115
3115
|
<div style="font-size: 14px; line-height: 2; color: var(--neiki-text-primary);">
|
|
3116
3116
|
<div><strong>${Utils.escapeHTML(t('help.author'))}:</strong> neikiri (Jindřich Stoklasa)</div>
|
|
3117
|
-
<div><strong>${Utils.escapeHTML(t('help.version'))}:</strong> 3.
|
|
3117
|
+
<div><strong>${Utils.escapeHTML(t('help.version'))}:</strong> 3.6.0</div>
|
|
3118
3118
|
<div><strong>${Utils.escapeHTML(t('help.github'))}:</strong> <a href="https://github.com/neikiri/neiki-editor" target="_blank" rel="noopener noreferrer" style="color: var(--neiki-accent);">github.com/neikiri/neiki-editor</a></div>
|
|
3119
3119
|
<div><strong>${Utils.escapeHTML(t('help.documentation'))}:</strong> <a href="https://github.com/neikiri/neiki-editor/wiki" target="_blank" rel="noopener noreferrer" style="color: var(--neiki-accent);">Wiki</a></div>
|
|
3120
3120
|
</div>
|
|
@@ -3900,6 +3900,24 @@
|
|
|
3900
3900
|
if (!Utils.isSafeUrl(url)) return;
|
|
3901
3901
|
const selection = Utils.getSelection();
|
|
3902
3902
|
const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
|
|
3903
|
+
const existingLink = this.editor.getLinkAtSelection();
|
|
3904
|
+
|
|
3905
|
+
if (existingLink) {
|
|
3906
|
+
existingLink.setAttribute('href', url);
|
|
3907
|
+
existingLink.textContent = text || url;
|
|
3908
|
+
if (newTab) {
|
|
3909
|
+
existingLink.setAttribute('target', '_blank');
|
|
3910
|
+
existingLink.setAttribute('rel', 'noopener noreferrer');
|
|
3911
|
+
} else {
|
|
3912
|
+
existingLink.removeAttribute('target');
|
|
3913
|
+
existingLink.removeAttribute('rel');
|
|
3914
|
+
}
|
|
3915
|
+
|
|
3916
|
+
this.editor.history.record();
|
|
3917
|
+
this.editor.syncToOriginal();
|
|
3918
|
+
this.editor.triggerChange();
|
|
3919
|
+
return;
|
|
3920
|
+
}
|
|
3903
3921
|
|
|
3904
3922
|
if (range && !range.collapsed) {
|
|
3905
3923
|
this.exec('createLink', url);
|
|
@@ -4499,7 +4517,7 @@
|
|
|
4499
4517
|
const insertItems = [
|
|
4500
4518
|
{
|
|
4501
4519
|
key: 'link', icon: Icons.link, labelKey: 'insert.link',
|
|
4502
|
-
action: () => { this.saveCurrentSelection(); this.modal.open('link',
|
|
4520
|
+
action: () => { this.saveCurrentSelection(); this.modal.open('link', this.getLinkModalData()); }
|
|
4503
4521
|
},
|
|
4504
4522
|
{
|
|
4505
4523
|
key: 'image', icon: Icons.image, labelKey: 'insert.image',
|
|
@@ -4879,8 +4897,7 @@
|
|
|
4879
4897
|
let data = {};
|
|
4880
4898
|
|
|
4881
4899
|
if (item === 'link') {
|
|
4882
|
-
|
|
4883
|
-
data.text = sel.toString();
|
|
4900
|
+
data = this.getLinkModalData();
|
|
4884
4901
|
}
|
|
4885
4902
|
|
|
4886
4903
|
this.modal.open(item, data);
|
|
@@ -4910,6 +4927,13 @@
|
|
|
4910
4927
|
}
|
|
4911
4928
|
|
|
4912
4929
|
handleKeydown(e) {
|
|
4930
|
+
if ((e.key === 'ArrowUp' || e.key === 'ArrowDown') &&
|
|
4931
|
+
this.imageResizer &&
|
|
4932
|
+
this.imageResizer.moveCaretFromSelectedImage(e.key === 'ArrowUp' ? 'before' : 'after')) {
|
|
4933
|
+
e.preventDefault();
|
|
4934
|
+
return;
|
|
4935
|
+
}
|
|
4936
|
+
|
|
4913
4937
|
if ((e.key === 'Backspace' || e.key === 'Delete') &&
|
|
4914
4938
|
this.imageResizer &&
|
|
4915
4939
|
this.imageResizer.deleteSelectedImage()) {
|
|
@@ -4935,7 +4959,7 @@
|
|
|
4935
4959
|
case 'k':
|
|
4936
4960
|
e.preventDefault();
|
|
4937
4961
|
this.saveCurrentSelection();
|
|
4938
|
-
this.modal.open('link',
|
|
4962
|
+
this.modal.open('link', this.getLinkModalData());
|
|
4939
4963
|
break;
|
|
4940
4964
|
case 'z':
|
|
4941
4965
|
e.preventDefault();
|
|
@@ -4997,6 +5021,37 @@
|
|
|
4997
5021
|
}
|
|
4998
5022
|
}
|
|
4999
5023
|
|
|
5024
|
+
getLinkAtSelection() {
|
|
5025
|
+
const selection = window.getSelection();
|
|
5026
|
+
if (!selection || !selection.rangeCount) return null;
|
|
5027
|
+
|
|
5028
|
+
const range = selection.getRangeAt(0);
|
|
5029
|
+
if (!Utils.isRangeInside(range, this.contentArea)) return null;
|
|
5030
|
+
|
|
5031
|
+
const getClosestLink = (node) => {
|
|
5032
|
+
const element = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
|
|
5033
|
+
const link = element && element.closest ? element.closest('a') : null;
|
|
5034
|
+
return link && this.contentArea.contains(link) ? link : null;
|
|
5035
|
+
};
|
|
5036
|
+
|
|
5037
|
+
const startLink = getClosestLink(range.startContainer);
|
|
5038
|
+
const endLink = getClosestLink(range.endContainer);
|
|
5039
|
+
return startLink && startLink === endLink ? startLink : null;
|
|
5040
|
+
}
|
|
5041
|
+
|
|
5042
|
+
getLinkModalData() {
|
|
5043
|
+
const link = this.getLinkAtSelection();
|
|
5044
|
+
if (link) {
|
|
5045
|
+
return {
|
|
5046
|
+
url: link.getAttribute('href') || '',
|
|
5047
|
+
text: link.textContent || '',
|
|
5048
|
+
newTab: link.getAttribute('target') === '_blank'
|
|
5049
|
+
};
|
|
5050
|
+
}
|
|
5051
|
+
|
|
5052
|
+
return { text: Utils.getSelection().toString() };
|
|
5053
|
+
}
|
|
5054
|
+
|
|
5000
5055
|
handlePaste(e) {
|
|
5001
5056
|
// Check for pasted images first
|
|
5002
5057
|
if (e.clipboardData && e.clipboardData.files.length > 0) {
|
|
@@ -6313,6 +6368,9 @@
|
|
|
6313
6368
|
this.currentImg = img;
|
|
6314
6369
|
const isVideo = img.tagName === 'VIDEO';
|
|
6315
6370
|
|
|
6371
|
+
// Keep keyboard events in the editor while the media selection is active.
|
|
6372
|
+
this.editor.contentArea.focus({ preventScroll: true });
|
|
6373
|
+
|
|
6316
6374
|
// Create wrapper around image
|
|
6317
6375
|
this.wrapper = document.createElement('span');
|
|
6318
6376
|
this.wrapper.className = 'neiki-img-resizable';
|
|
@@ -6645,6 +6703,30 @@
|
|
|
6645
6703
|
if (sel) sel.removeAllRanges();
|
|
6646
6704
|
}
|
|
6647
6705
|
|
|
6706
|
+
moveCaretFromSelectedImage(position) {
|
|
6707
|
+
if (!this.currentImg || !this.wrapper || !this.editor.contentArea.contains(this.wrapper)) {
|
|
6708
|
+
return false;
|
|
6709
|
+
}
|
|
6710
|
+
|
|
6711
|
+
const img = this.currentImg;
|
|
6712
|
+
this.deselect();
|
|
6713
|
+
|
|
6714
|
+
const range = document.createRange();
|
|
6715
|
+
if (position === 'before') {
|
|
6716
|
+
range.setStartBefore(img);
|
|
6717
|
+
} else {
|
|
6718
|
+
range.setStartAfter(img);
|
|
6719
|
+
}
|
|
6720
|
+
range.collapse(true);
|
|
6721
|
+
|
|
6722
|
+
const selection = window.getSelection();
|
|
6723
|
+
selection.removeAllRanges();
|
|
6724
|
+
selection.addRange(range);
|
|
6725
|
+
this.editor.savedSelectionRange = range.cloneRange();
|
|
6726
|
+
this.editor.updateToolbar();
|
|
6727
|
+
return true;
|
|
6728
|
+
}
|
|
6729
|
+
|
|
6648
6730
|
getSelectedImageClipboardData() {
|
|
6649
6731
|
if (!this.currentImg || !this.wrapper || !this.editor.contentArea.contains(this.wrapper)) {
|
|
6650
6732
|
return null;
|
|
@@ -7104,7 +7186,9 @@
|
|
|
7104
7186
|
if (prev && prev.parentNode === this.editor.contentArea) {
|
|
7105
7187
|
prev.parentNode.insertBefore(block, prev);
|
|
7106
7188
|
this.editor.history.record();
|
|
7189
|
+
this.editor.syncToOriginal();
|
|
7107
7190
|
this.editor.triggerChange();
|
|
7191
|
+
this.editor.updateStatusBar();
|
|
7108
7192
|
}
|
|
7109
7193
|
}
|
|
7110
7194
|
|
|
@@ -7115,7 +7199,9 @@
|
|
|
7115
7199
|
if (next && next.parentNode === this.editor.contentArea) {
|
|
7116
7200
|
next.parentNode.insertBefore(block, next.nextSibling);
|
|
7117
7201
|
this.editor.history.record();
|
|
7202
|
+
this.editor.syncToOriginal();
|
|
7118
7203
|
this.editor.triggerChange();
|
|
7204
|
+
this.editor.updateStatusBar();
|
|
7119
7205
|
}
|
|
7120
7206
|
}
|
|
7121
7207
|
|
|
@@ -7281,8 +7367,7 @@
|
|
|
7281
7367
|
|
|
7282
7368
|
handleButtonClick(item) {
|
|
7283
7369
|
if (item === 'link') {
|
|
7284
|
-
|
|
7285
|
-
this.editor.modal.open('link', { text: sel.toString() });
|
|
7370
|
+
this.editor.modal.open('link', this.editor.getLinkModalData());
|
|
7286
7371
|
} else if (item === 'moveUp') {
|
|
7287
7372
|
if (this.editor.blockDragDrop) this.editor.blockDragDrop.moveBlockUp();
|
|
7288
7373
|
} else if (item === 'moveDown') {
|