lakelib 0.2.1 → 0.2.3
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/dist/lake.css +149 -117
- package/dist/lake.min.js +29 -21
- package/dist/lake.min.js.map +1 -1
- package/lib/lake.css +149 -117
- package/lib/lake.js +791 -453
- package/lib/lake.js.map +1 -1
- package/lib/types/boxes/mention.d.ts +3 -0
- package/lib/types/css/index.d.ts +3 -1
- package/lib/types/editor.d.ts +1 -3
- package/lib/types/index.d.ts +2 -1
- package/lib/types/models/range.d.ts +1 -0
- package/lib/types/plugins/link.d.ts +1 -1
- package/lib/types/plugins/mention.d.ts +3 -0
- package/lib/types/types/box-toolbar.d.ts +0 -8
- package/lib/types/types/dropdown.d.ts +4 -1
- package/lib/types/types/mention.d.ts +6 -0
- package/lib/types/types/request.d.ts +2 -2
- package/lib/types/ui/box-toolbar.d.ts +13 -3
- package/lib/types/ui/dropdown.d.ts +11 -4
- package/lib/types/ui/link-popup.d.ts +6 -4
- package/lib/types/ui/mention-menu.d.ts +14 -0
- package/lib/types/ui/menu.d.ts +33 -0
- package/lib/types/ui/slash-menu.d.ts +18 -0
- package/package.json +1 -1
- package/lib/types/ui/slash-popup.d.ts +0 -36
package/lib/lake.js
CHANGED
|
@@ -813,8 +813,8 @@ class Nodes {
|
|
|
813
813
|
// Traverses the first node and its parents until it finds an element which can scroll.
|
|
814
814
|
closestScroller() {
|
|
815
815
|
let parent = this.eq(0);
|
|
816
|
-
while (parent.length > 0
|
|
817
|
-
if (['scroll', 'auto'].indexOf(parent.computedCSS('overflow-y')) >= 0) {
|
|
816
|
+
while (parent.length > 0) {
|
|
817
|
+
if (parent.isElement && ['scroll', 'auto'].indexOf(parent.computedCSS('overflow-y')) >= 0) {
|
|
818
818
|
return parent;
|
|
819
819
|
}
|
|
820
820
|
parent = parent.parent();
|
|
@@ -1828,7 +1828,7 @@ class Range {
|
|
|
1828
1828
|
return marks;
|
|
1829
1829
|
}
|
|
1830
1830
|
// Returns the text of the start part of the closest block divided into two parts by the start point of the range.
|
|
1831
|
-
// "<p>one<anchor />two<focus />three</p>" returns "
|
|
1831
|
+
// "<p>one<anchor />two<focus />three</p>" returns "one".
|
|
1832
1832
|
getStartText() {
|
|
1833
1833
|
const node = this.startNode;
|
|
1834
1834
|
const offset = this.startOffset;
|
|
@@ -1873,6 +1873,45 @@ class Range {
|
|
|
1873
1873
|
}
|
|
1874
1874
|
return text;
|
|
1875
1875
|
}
|
|
1876
|
+
// Returns a new text range from the specified character to the beginning of the current range.
|
|
1877
|
+
// The specified character must be preceded by a whitespace or be at the beginning of a paragraph,
|
|
1878
|
+
// without being adjacent to other characters. If these conditions are not met, it returns null.
|
|
1879
|
+
getCharacterRange(character) {
|
|
1880
|
+
const newRange = this.clone();
|
|
1881
|
+
newRange.shrink();
|
|
1882
|
+
if (newRange.startOffset === 0) {
|
|
1883
|
+
return null;
|
|
1884
|
+
}
|
|
1885
|
+
if (newRange.startNode.isElement) {
|
|
1886
|
+
const textNode = newRange.startNode.children()[newRange.startOffset - 1];
|
|
1887
|
+
if (!textNode.isText) {
|
|
1888
|
+
return null;
|
|
1889
|
+
}
|
|
1890
|
+
newRange.setEnd(textNode, textNode.text().length);
|
|
1891
|
+
newRange.collapseToEnd();
|
|
1892
|
+
}
|
|
1893
|
+
const textNode = newRange.startNode;
|
|
1894
|
+
const text = textNode.text().slice(0, newRange.startOffset);
|
|
1895
|
+
const lastIndexOfNormalSpace = text.lastIndexOf(` ${character}`);
|
|
1896
|
+
const lastIndexOfNoBreakSpace = text.lastIndexOf(`\xA0${character}`);
|
|
1897
|
+
const lastIndexOfZeroWidthSpace = text.lastIndexOf(`\u200B${character}`);
|
|
1898
|
+
if (lastIndexOfNormalSpace >= 0) {
|
|
1899
|
+
newRange.setStart(textNode, lastIndexOfNormalSpace + 1);
|
|
1900
|
+
}
|
|
1901
|
+
else if (lastIndexOfNoBreakSpace >= 0) {
|
|
1902
|
+
newRange.setStart(textNode, lastIndexOfNoBreakSpace + 1);
|
|
1903
|
+
}
|
|
1904
|
+
else if (lastIndexOfZeroWidthSpace >= 0) {
|
|
1905
|
+
newRange.setStart(textNode, lastIndexOfZeroWidthSpace + 1);
|
|
1906
|
+
}
|
|
1907
|
+
else if (text.indexOf(character) === 0) {
|
|
1908
|
+
newRange.setStart(textNode, 0);
|
|
1909
|
+
}
|
|
1910
|
+
else {
|
|
1911
|
+
return null;
|
|
1912
|
+
}
|
|
1913
|
+
return newRange;
|
|
1914
|
+
}
|
|
1876
1915
|
// Returns a range object with boundary points identical to the cloned range.
|
|
1877
1916
|
clone() {
|
|
1878
1917
|
return new Range(this.range.cloneRange());
|
|
@@ -3422,7 +3461,7 @@ loadAllLocales();
|
|
|
3422
3461
|
|
|
3423
3462
|
class Dropdown {
|
|
3424
3463
|
constructor(config) {
|
|
3425
|
-
this.
|
|
3464
|
+
this.clickListener = (event) => {
|
|
3426
3465
|
const targetNode = new Nodes(event.target);
|
|
3427
3466
|
const titleNode = this.node.find('.lake-dropdown-title');
|
|
3428
3467
|
if (targetNode.closest('.lake-dropdown-title').get(0) === titleNode.get(0)) {
|
|
@@ -3430,18 +3469,22 @@ class Dropdown {
|
|
|
3430
3469
|
}
|
|
3431
3470
|
this.hideMenu();
|
|
3432
3471
|
};
|
|
3472
|
+
this.scrollListener = () => this.updatePosition();
|
|
3473
|
+
this.resizeListener = () => this.updatePosition();
|
|
3433
3474
|
this.config = config;
|
|
3434
3475
|
this.root = config.root;
|
|
3435
3476
|
this.locale = config.locale || i18nObject('en-US');
|
|
3436
|
-
|
|
3477
|
+
this.location = config.location || 'local';
|
|
3478
|
+
this.direction = config.direction || 'auto';
|
|
3437
3479
|
this.node = query(safeTemplate `
|
|
3438
|
-
<div class="lake-dropdown lake-${config.menuType}-dropdown" name="${config.name}"
|
|
3480
|
+
<div class="lake-dropdown lake-${config.menuType}-dropdown" name="${config.name}">
|
|
3439
3481
|
<button type="button" name="${config.name}" class="lake-dropdown-title">
|
|
3440
3482
|
<div class="lake-dropdown-${config.icon ? 'icon' : 'text'}"></div>
|
|
3441
3483
|
<div class="lake-dropdown-down-icon"></div>
|
|
3442
3484
|
</button>
|
|
3443
3485
|
</div>
|
|
3444
3486
|
`);
|
|
3487
|
+
this.menuNode = query('<ul class="lake-popup lake-dropdown-menu lake-custom-properties" />');
|
|
3445
3488
|
if (config.tabIndex !== undefined) {
|
|
3446
3489
|
const titleNode = this.node.find('.lake-dropdown-title');
|
|
3447
3490
|
titleNode.attr('tabindex', config.tabIndex.toString());
|
|
@@ -3520,14 +3563,97 @@ class Dropdown {
|
|
|
3520
3563
|
}
|
|
3521
3564
|
}
|
|
3522
3565
|
}
|
|
3566
|
+
appendMenu() {
|
|
3567
|
+
const config = this.config;
|
|
3568
|
+
const menuNode = this.menuNode;
|
|
3569
|
+
const titleNode = this.node.find('.lake-dropdown-title');
|
|
3570
|
+
const textNode = titleNode.find('.lake-dropdown-text');
|
|
3571
|
+
menuNode.addClass(`lake-${config.menuType}-dropdown-menu`);
|
|
3572
|
+
if (config.menuWidth) {
|
|
3573
|
+
menuNode.css('width', config.menuWidth);
|
|
3574
|
+
}
|
|
3575
|
+
if (config.menuHeight) {
|
|
3576
|
+
menuNode.addClass('lake-dropdown-menu-with-scroll');
|
|
3577
|
+
menuNode.css('height', config.menuHeight);
|
|
3578
|
+
}
|
|
3579
|
+
this.apppendMenuItems(menuNode);
|
|
3580
|
+
if (this.location === 'local') {
|
|
3581
|
+
this.node.append(menuNode);
|
|
3582
|
+
}
|
|
3583
|
+
else {
|
|
3584
|
+
query(document.body).append(menuNode);
|
|
3585
|
+
}
|
|
3586
|
+
menuNode.on('click', event => {
|
|
3587
|
+
event.preventDefault();
|
|
3588
|
+
event.stopPropagation();
|
|
3589
|
+
const listItem = query(event.target).closest('li');
|
|
3590
|
+
if (listItem.length === 0) {
|
|
3591
|
+
return;
|
|
3592
|
+
}
|
|
3593
|
+
const value = listItem.attr('value');
|
|
3594
|
+
Dropdown.setValue(this.node, [value]);
|
|
3595
|
+
if (textNode.length > 0) {
|
|
3596
|
+
textNode.text(listItem.text());
|
|
3597
|
+
}
|
|
3598
|
+
if (config.menuType === 'color' && value !== '') {
|
|
3599
|
+
this.node.attr('color', value);
|
|
3600
|
+
this.updateColorAccent(titleNode, value);
|
|
3601
|
+
}
|
|
3602
|
+
config.onSelect(value);
|
|
3603
|
+
this.hideMenu();
|
|
3604
|
+
});
|
|
3605
|
+
}
|
|
3606
|
+
updatePosition() {
|
|
3607
|
+
const menuNode = this.menuNode;
|
|
3608
|
+
const dropdownNativeNode = this.node.get(0);
|
|
3609
|
+
const dropdownRect = dropdownNativeNode.getBoundingClientRect();
|
|
3610
|
+
// A overflow width on the left side, greater than 0 indicates an overflow.
|
|
3611
|
+
const leftOverflow = menuNode.width() - (dropdownRect.x + dropdownRect.width);
|
|
3612
|
+
// A overflow width on the right side, greater than 0 indicates an overflow.
|
|
3613
|
+
const rightOverflow = dropdownRect.x + menuNode.width() - window.innerWidth;
|
|
3614
|
+
const rightToLeft = rightOverflow + 50 > 0 && (leftOverflow < 0 || leftOverflow < rightOverflow);
|
|
3615
|
+
if (this.location === 'local') {
|
|
3616
|
+
if (rightToLeft) {
|
|
3617
|
+
menuNode.css('left', 'auto');
|
|
3618
|
+
menuNode.css('right', '0');
|
|
3619
|
+
}
|
|
3620
|
+
else {
|
|
3621
|
+
menuNode.css('left', '');
|
|
3622
|
+
menuNode.css('right', '');
|
|
3623
|
+
}
|
|
3624
|
+
if (this.direction === 'top') {
|
|
3625
|
+
menuNode.css('top', 'auto');
|
|
3626
|
+
menuNode.css('bottom', `${dropdownRect.height}px`);
|
|
3627
|
+
}
|
|
3628
|
+
return;
|
|
3629
|
+
}
|
|
3630
|
+
// A overflow width on the bottom side, greater than 0 indicates an overflow.
|
|
3631
|
+
const bottomOverflow = dropdownRect.y + dropdownRect.height + menuNode.height() - window.innerHeight;
|
|
3632
|
+
const dropdownX = dropdownRect.x + window.scrollX;
|
|
3633
|
+
const dropdownY = dropdownRect.y + window.scrollY;
|
|
3634
|
+
if (rightToLeft) {
|
|
3635
|
+
menuNode.css('left', `${dropdownX - menuNode.width() + dropdownRect.width}px`);
|
|
3636
|
+
}
|
|
3637
|
+
else {
|
|
3638
|
+
menuNode.css('left', `${dropdownX}px`);
|
|
3639
|
+
}
|
|
3640
|
+
if (bottomOverflow > 0) {
|
|
3641
|
+
menuNode.css('top', `${dropdownY - menuNode.height()}px`);
|
|
3642
|
+
}
|
|
3643
|
+
else {
|
|
3644
|
+
menuNode.css('top', `${dropdownY + dropdownRect.height}px`);
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3523
3647
|
showMenu() {
|
|
3524
3648
|
const config = this.config;
|
|
3525
|
-
const
|
|
3526
|
-
|
|
3527
|
-
|
|
3649
|
+
const menuNode = this.menuNode;
|
|
3650
|
+
if (!menuNode.get(0).isConnected) {
|
|
3651
|
+
this.appendMenu();
|
|
3652
|
+
}
|
|
3653
|
+
if (this.node.attr('disabled')) {
|
|
3528
3654
|
return;
|
|
3529
3655
|
}
|
|
3530
|
-
const currentValues = Dropdown.getValue(
|
|
3656
|
+
const currentValues = Dropdown.getValue(this.node);
|
|
3531
3657
|
menuNode.find('.lake-dropdown-menu-check').css('visibility', 'hidden');
|
|
3532
3658
|
menuNode.find('li').each(node => {
|
|
3533
3659
|
const listNode = query(node);
|
|
@@ -3537,40 +3663,62 @@ class Dropdown {
|
|
|
3537
3663
|
});
|
|
3538
3664
|
menuNode.css('visibility', 'hidden');
|
|
3539
3665
|
menuNode.show(config.menuType === 'list' ? 'block' : 'flex');
|
|
3540
|
-
|
|
3541
|
-
const
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
// A overflow width on the right side, greater than 0 indicates an overflow.
|
|
3545
|
-
const rightOverflow = dropdownRect.x + menuNode.width() - window.innerWidth;
|
|
3546
|
-
if (rightOverflow + 50 > 0 && (leftOverflow < 0 || leftOverflow < rightOverflow)) {
|
|
3547
|
-
menuNode.css('left', 'auto');
|
|
3548
|
-
menuNode.css('right', '0');
|
|
3549
|
-
}
|
|
3550
|
-
else {
|
|
3551
|
-
menuNode.css('left', '');
|
|
3552
|
-
menuNode.css('right', '');
|
|
3666
|
+
this.updatePosition();
|
|
3667
|
+
const viewport = this.node.closestScroller();
|
|
3668
|
+
if (viewport.length > 0) {
|
|
3669
|
+
viewport.on('scroll', this.scrollListener);
|
|
3553
3670
|
}
|
|
3671
|
+
document.addEventListener('click', this.clickListener);
|
|
3672
|
+
window.addEventListener('resize', this.resizeListener);
|
|
3554
3673
|
menuNode.css('visibility', '');
|
|
3555
|
-
document.addEventListener('click', this.documentClickListener);
|
|
3556
3674
|
}
|
|
3557
3675
|
hideMenu() {
|
|
3558
|
-
|
|
3559
|
-
const
|
|
3560
|
-
|
|
3561
|
-
|
|
3676
|
+
this.menuNode.hide();
|
|
3677
|
+
const viewport = this.node.closestScroller();
|
|
3678
|
+
if (viewport.length > 0) {
|
|
3679
|
+
viewport.off('scroll', this.scrollListener);
|
|
3680
|
+
}
|
|
3681
|
+
document.removeEventListener('click', this.clickListener);
|
|
3682
|
+
window.removeEventListener('resize', this.resizeListener);
|
|
3562
3683
|
}
|
|
3563
|
-
|
|
3684
|
+
render() {
|
|
3685
|
+
var _a, _b;
|
|
3564
3686
|
const config = this.config;
|
|
3565
|
-
const
|
|
3566
|
-
const titleNode =
|
|
3687
|
+
const defaultValue = (_a = config.defaultValue) !== null && _a !== void 0 ? _a : '';
|
|
3688
|
+
const titleNode = this.node.find('.lake-dropdown-title');
|
|
3689
|
+
if (!config.downIcon) {
|
|
3690
|
+
titleNode.addClass('lake-dropdown-title-no-down');
|
|
3691
|
+
}
|
|
3692
|
+
if (config.width) {
|
|
3693
|
+
titleNode.css('width', config.width);
|
|
3694
|
+
}
|
|
3695
|
+
const tooltip = typeof config.tooltip === 'string' ? config.tooltip : config.tooltip(this.locale);
|
|
3696
|
+
titleNode.attr('title', tooltip);
|
|
3567
3697
|
const textNode = titleNode.find('.lake-dropdown-text');
|
|
3568
3698
|
const iconNode = titleNode.find('.lake-dropdown-icon');
|
|
3699
|
+
if (config.icon) {
|
|
3700
|
+
iconNode.append(config.icon);
|
|
3701
|
+
}
|
|
3702
|
+
if (config.accentIcon) {
|
|
3703
|
+
iconNode.append(config.accentIcon);
|
|
3704
|
+
}
|
|
3569
3705
|
const downIconNode = titleNode.find('.lake-dropdown-down-icon');
|
|
3570
|
-
|
|
3706
|
+
if (config.downIcon) {
|
|
3707
|
+
downIconNode.append(config.downIcon);
|
|
3708
|
+
}
|
|
3709
|
+
Dropdown.setValue(this.node, [defaultValue]);
|
|
3710
|
+
if (textNode.length > 0) {
|
|
3711
|
+
const menuMap = Dropdown.getMenuMap(config.menuItems, this.locale);
|
|
3712
|
+
textNode.text((_b = menuMap.get(defaultValue)) !== null && _b !== void 0 ? _b : defaultValue);
|
|
3713
|
+
}
|
|
3714
|
+
if (config.menuType === 'color') {
|
|
3715
|
+
this.updateColorAccent(titleNode, defaultValue);
|
|
3716
|
+
}
|
|
3717
|
+
this.node.append(titleNode);
|
|
3718
|
+
this.root.append(this.node);
|
|
3571
3719
|
if (config.menuType === 'color') {
|
|
3572
3720
|
iconNode.on('mouseenter', () => {
|
|
3573
|
-
if (
|
|
3721
|
+
if (this.node.attr('disabled')) {
|
|
3574
3722
|
return;
|
|
3575
3723
|
}
|
|
3576
3724
|
iconNode.addClass('lake-dropdown-icon-hovered');
|
|
@@ -3579,7 +3727,7 @@ class Dropdown {
|
|
|
3579
3727
|
iconNode.removeClass('lake-dropdown-icon-hovered');
|
|
3580
3728
|
});
|
|
3581
3729
|
downIconNode.on('mouseenter', () => {
|
|
3582
|
-
if (
|
|
3730
|
+
if (this.node.attr('disabled')) {
|
|
3583
3731
|
return;
|
|
3584
3732
|
}
|
|
3585
3733
|
downIconNode.addClass('lake-dropdown-down-icon-hovered');
|
|
@@ -3590,7 +3738,7 @@ class Dropdown {
|
|
|
3590
3738
|
}
|
|
3591
3739
|
else {
|
|
3592
3740
|
titleNode.on('mouseenter', () => {
|
|
3593
|
-
if (
|
|
3741
|
+
if (this.node.attr('disabled')) {
|
|
3594
3742
|
return;
|
|
3595
3743
|
}
|
|
3596
3744
|
titleNode.addClass('lake-dropdown-title-hovered');
|
|
@@ -3602,10 +3750,10 @@ class Dropdown {
|
|
|
3602
3750
|
if (config.menuType === 'color') {
|
|
3603
3751
|
iconNode.on('click', event => {
|
|
3604
3752
|
event.preventDefault();
|
|
3605
|
-
if (
|
|
3753
|
+
if (this.node.attr('disabled')) {
|
|
3606
3754
|
return;
|
|
3607
3755
|
}
|
|
3608
|
-
const value =
|
|
3756
|
+
const value = this.node.attr('color') || config.defaultValue || '';
|
|
3609
3757
|
config.onSelect(value);
|
|
3610
3758
|
});
|
|
3611
3759
|
}
|
|
@@ -3614,74 +3762,6 @@ class Dropdown {
|
|
|
3614
3762
|
event.preventDefault();
|
|
3615
3763
|
this.showMenu();
|
|
3616
3764
|
});
|
|
3617
|
-
menuNode.on('click', event => {
|
|
3618
|
-
event.preventDefault();
|
|
3619
|
-
event.stopPropagation();
|
|
3620
|
-
const listItem = query(event.target).closest('li');
|
|
3621
|
-
if (listItem.length === 0) {
|
|
3622
|
-
return;
|
|
3623
|
-
}
|
|
3624
|
-
const value = listItem.attr('value');
|
|
3625
|
-
Dropdown.setValue(dropdownNode, [value]);
|
|
3626
|
-
if (textNode.length > 0) {
|
|
3627
|
-
textNode.text(listItem.text());
|
|
3628
|
-
}
|
|
3629
|
-
if (config.menuType === 'color' && value !== '') {
|
|
3630
|
-
dropdownNode.attr('color', value);
|
|
3631
|
-
this.updateColorAccent(titleNode, value);
|
|
3632
|
-
}
|
|
3633
|
-
config.onSelect(value);
|
|
3634
|
-
this.hideMenu();
|
|
3635
|
-
});
|
|
3636
|
-
}
|
|
3637
|
-
render() {
|
|
3638
|
-
var _a, _b;
|
|
3639
|
-
const config = this.config;
|
|
3640
|
-
const defaultValue = (_a = config.defaultValue) !== null && _a !== void 0 ? _a : '';
|
|
3641
|
-
const dropdownNode = this.node;
|
|
3642
|
-
const titleNode = dropdownNode.find('.lake-dropdown-title');
|
|
3643
|
-
if (!config.downIcon) {
|
|
3644
|
-
titleNode.addClass('lake-dropdown-title-no-down');
|
|
3645
|
-
}
|
|
3646
|
-
if (config.width) {
|
|
3647
|
-
titleNode.css('width', config.width);
|
|
3648
|
-
}
|
|
3649
|
-
const tooltip = typeof config.tooltip === 'string' ? config.tooltip : config.tooltip(this.locale);
|
|
3650
|
-
titleNode.attr('title', tooltip);
|
|
3651
|
-
const textNode = titleNode.find('.lake-dropdown-text');
|
|
3652
|
-
const iconNode = titleNode.find('.lake-dropdown-icon');
|
|
3653
|
-
if (config.icon) {
|
|
3654
|
-
iconNode.append(config.icon);
|
|
3655
|
-
}
|
|
3656
|
-
if (config.accentIcon) {
|
|
3657
|
-
iconNode.append(config.accentIcon);
|
|
3658
|
-
}
|
|
3659
|
-
const downIconNode = titleNode.find('.lake-dropdown-down-icon');
|
|
3660
|
-
if (config.downIcon) {
|
|
3661
|
-
downIconNode.append(config.downIcon);
|
|
3662
|
-
}
|
|
3663
|
-
const menuNode = query('<ul class="lake-dropdown-menu" />');
|
|
3664
|
-
menuNode.addClass(`lake-${config.menuType}-dropdown-menu`);
|
|
3665
|
-
if (config.menuWidth) {
|
|
3666
|
-
menuNode.css('width', config.menuWidth);
|
|
3667
|
-
}
|
|
3668
|
-
if (config.menuHeight) {
|
|
3669
|
-
menuNode.addClass('lake-dropdown-menu-with-scroll');
|
|
3670
|
-
menuNode.css('height', config.menuHeight);
|
|
3671
|
-
}
|
|
3672
|
-
Dropdown.setValue(dropdownNode, [defaultValue]);
|
|
3673
|
-
if (textNode.length > 0) {
|
|
3674
|
-
const menuMap = Dropdown.getMenuMap(config.menuItems, this.locale);
|
|
3675
|
-
textNode.text((_b = menuMap.get(defaultValue)) !== null && _b !== void 0 ? _b : defaultValue);
|
|
3676
|
-
}
|
|
3677
|
-
if (config.menuType === 'color') {
|
|
3678
|
-
this.updateColorAccent(titleNode, defaultValue);
|
|
3679
|
-
}
|
|
3680
|
-
this.apppendMenuItems(menuNode);
|
|
3681
|
-
dropdownNode.append(titleNode);
|
|
3682
|
-
dropdownNode.append(menuNode);
|
|
3683
|
-
this.root.append(dropdownNode);
|
|
3684
|
-
this.bindEvents();
|
|
3685
3765
|
}
|
|
3686
3766
|
unmount() {
|
|
3687
3767
|
this.hideMenu();
|
|
@@ -3694,12 +3774,13 @@ class BoxToolbar {
|
|
|
3694
3774
|
this.buttonItemList = [];
|
|
3695
3775
|
this.dropdownItemList = [];
|
|
3696
3776
|
this.dropdownList = [];
|
|
3697
|
-
this.
|
|
3777
|
+
this.scrollListener = () => this.updatePosition();
|
|
3778
|
+
this.resizeListener = () => this.updatePosition();
|
|
3698
3779
|
this.box = config.box;
|
|
3699
3780
|
this.items = config.items;
|
|
3700
3781
|
this.locale = config.locale || i18nObject('en-US');
|
|
3701
3782
|
this.placement = config.placement || 'top';
|
|
3702
|
-
this.container = query('<div class="lake-box-toolbar" />');
|
|
3783
|
+
this.container = query('<div class="lake-popup lake-box-toolbar lake-custom-properties" />');
|
|
3703
3784
|
}
|
|
3704
3785
|
appendDivider() {
|
|
3705
3786
|
this.container.append('<div class="lake-toolbar-divider" />');
|
|
@@ -3731,7 +3812,7 @@ class BoxToolbar {
|
|
|
3731
3812
|
menuType: item.menuType,
|
|
3732
3813
|
menuItems: item.menuItems,
|
|
3733
3814
|
tabIndex: -1,
|
|
3734
|
-
|
|
3815
|
+
direction: this.placement === 'top' ? 'bottom' : 'top',
|
|
3735
3816
|
onSelect: value => {
|
|
3736
3817
|
item.onSelect(this.box, value);
|
|
3737
3818
|
},
|
|
@@ -3739,7 +3820,7 @@ class BoxToolbar {
|
|
|
3739
3820
|
dropdown.render();
|
|
3740
3821
|
this.dropdownList.push(dropdown);
|
|
3741
3822
|
}
|
|
3742
|
-
|
|
3823
|
+
updatePosition() {
|
|
3743
3824
|
const boxNode = this.box.node;
|
|
3744
3825
|
const boxNativeNode = boxNode.get(0);
|
|
3745
3826
|
const boxRect = boxNativeNode.getBoundingClientRect();
|
|
@@ -3760,7 +3841,7 @@ class BoxToolbar {
|
|
|
3760
3841
|
}
|
|
3761
3842
|
// Renders a toolbar for the specified box.
|
|
3762
3843
|
render() {
|
|
3763
|
-
|
|
3844
|
+
query(document.body).append(this.container);
|
|
3764
3845
|
for (const item of this.items) {
|
|
3765
3846
|
if (item === '|') {
|
|
3766
3847
|
this.appendDivider();
|
|
@@ -3774,13 +3855,23 @@ class BoxToolbar {
|
|
|
3774
3855
|
this.appendDropdown(item);
|
|
3775
3856
|
}
|
|
3776
3857
|
}
|
|
3777
|
-
this.
|
|
3858
|
+
this.updatePosition();
|
|
3859
|
+
const viewport = this.box.node.closestScroller();
|
|
3860
|
+
if (viewport.length > 0) {
|
|
3861
|
+
viewport.on('scroll', this.scrollListener);
|
|
3862
|
+
}
|
|
3863
|
+
window.addEventListener('resize', this.resizeListener);
|
|
3778
3864
|
}
|
|
3779
3865
|
// Destroys the toolbar.
|
|
3780
3866
|
unmount() {
|
|
3781
3867
|
for (const dropdown of this.dropdownList) {
|
|
3782
3868
|
dropdown.unmount();
|
|
3783
3869
|
}
|
|
3870
|
+
const viewport = this.box.node.closestScroller();
|
|
3871
|
+
if (viewport.length > 0) {
|
|
3872
|
+
viewport.off('scroll', this.scrollListener);
|
|
3873
|
+
}
|
|
3874
|
+
window.removeEventListener('resize', this.resizeListener);
|
|
3784
3875
|
this.container.remove();
|
|
3785
3876
|
}
|
|
3786
3877
|
}
|
|
@@ -3900,31 +3991,19 @@ class Box {
|
|
|
3900
3991
|
}
|
|
3901
3992
|
catch ( /* empty */_a) { /* empty */ }
|
|
3902
3993
|
let toolbar = null;
|
|
3903
|
-
const scrollListener = () => {
|
|
3904
|
-
if (toolbar) {
|
|
3905
|
-
toolbar.position();
|
|
3906
|
-
}
|
|
3907
|
-
};
|
|
3908
3994
|
this.event.on('focus', () => {
|
|
3909
3995
|
toolbar = new BoxToolbar({
|
|
3910
|
-
root: editor ? editor.popupContainer : query(document.body),
|
|
3911
3996
|
box: this,
|
|
3912
3997
|
items,
|
|
3913
3998
|
locale: editor ? editor.locale : undefined,
|
|
3914
3999
|
});
|
|
3915
4000
|
toolbar.render();
|
|
3916
|
-
if (editor) {
|
|
3917
|
-
editor.root.on('scroll', scrollListener);
|
|
3918
|
-
}
|
|
3919
4001
|
});
|
|
3920
4002
|
this.event.on('blur', () => {
|
|
3921
4003
|
if (toolbar) {
|
|
3922
4004
|
toolbar.unmount();
|
|
3923
4005
|
toolbar = null;
|
|
3924
4006
|
}
|
|
3925
|
-
if (editor) {
|
|
3926
|
-
editor.root.off('scroll', scrollListener);
|
|
3927
|
-
}
|
|
3928
4007
|
});
|
|
3929
4008
|
}
|
|
3930
4009
|
// Renders the contents of the box.
|
|
@@ -4075,12 +4154,14 @@ function request(option) {
|
|
|
4075
4154
|
}
|
|
4076
4155
|
formData.append(key, value);
|
|
4077
4156
|
});
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4157
|
+
if (option.file) {
|
|
4158
|
+
const filename = option.filename || 'file';
|
|
4159
|
+
if (option.file instanceof Blob) {
|
|
4160
|
+
formData.append(filename, option.file, option.file.name);
|
|
4161
|
+
}
|
|
4162
|
+
else {
|
|
4163
|
+
formData.append(filename, option.file);
|
|
4164
|
+
}
|
|
4084
4165
|
}
|
|
4085
4166
|
xhr.onerror = (e) => {
|
|
4086
4167
|
if (option.onError) {
|
|
@@ -5294,6 +5375,7 @@ function insertBox(range, boxName, boxValue) {
|
|
|
5294
5375
|
fragment.appendChild(box.node.get(0));
|
|
5295
5376
|
// inline box
|
|
5296
5377
|
if (box.type === 'inline') {
|
|
5378
|
+
splitMarks(range);
|
|
5297
5379
|
insertFragment(range, fragment);
|
|
5298
5380
|
box.render();
|
|
5299
5381
|
range.selectBoxEnd(box.node);
|
|
@@ -5359,7 +5441,7 @@ function removeBox(range) {
|
|
|
5359
5441
|
return box;
|
|
5360
5442
|
}
|
|
5361
5443
|
|
|
5362
|
-
var version = "0.2.
|
|
5444
|
+
var version = "0.2.3";
|
|
5363
5445
|
|
|
5364
5446
|
// Returns the attributes of the element as an key-value object.
|
|
5365
5447
|
function getAttributes(node) {
|
|
@@ -5947,6 +6029,7 @@ const defaultConfig = {
|
|
|
5947
6029
|
}
|
|
5948
6030
|
},
|
|
5949
6031
|
slash: false,
|
|
6032
|
+
mention: false,
|
|
5950
6033
|
};
|
|
5951
6034
|
class Editor {
|
|
5952
6035
|
constructor(config) {
|
|
@@ -5962,6 +6045,7 @@ class Editor {
|
|
|
5962
6045
|
this.isComposing = false;
|
|
5963
6046
|
this.event = new EventEmitter();
|
|
5964
6047
|
this.box = Editor.box;
|
|
6048
|
+
this.popup = null;
|
|
5965
6049
|
this.copyListener = event => {
|
|
5966
6050
|
const range = this.selection.getCurrentRange();
|
|
5967
6051
|
if (!this.container.contains(range.commonAncestor)) {
|
|
@@ -5995,12 +6079,6 @@ class Editor {
|
|
|
5995
6079
|
}
|
|
5996
6080
|
this.event.emit('click', targetNode);
|
|
5997
6081
|
};
|
|
5998
|
-
this.resizeListener = () => {
|
|
5999
|
-
this.event.emit('resize');
|
|
6000
|
-
};
|
|
6001
|
-
this.scrollListener = () => {
|
|
6002
|
-
this.event.emit('scroll');
|
|
6003
|
-
};
|
|
6004
6082
|
this.updateSelectionRange = debounce(() => {
|
|
6005
6083
|
this.selection.updateByRange();
|
|
6006
6084
|
}, 1, {
|
|
@@ -6110,13 +6188,13 @@ class Editor {
|
|
|
6110
6188
|
this.containerWrapper = query('<div class="lake-container-wrapper" />');
|
|
6111
6189
|
this.container = query('<div class="lake-container" />');
|
|
6112
6190
|
this.overlayContainer = query('<div class="lake-overlay" />');
|
|
6113
|
-
this.popupContainer = query('<div class="lake-popup lake-custom-properties" />');
|
|
6114
6191
|
this.readonly = this.config.readonly;
|
|
6115
6192
|
this.root.addClass('lake-custom-properties');
|
|
6116
6193
|
this.container.attr({
|
|
6117
6194
|
contenteditable: this.readonly ? 'false' : 'true',
|
|
6118
6195
|
spellcheck: this.config.spellcheck ? 'true' : 'false',
|
|
6119
6196
|
tabindex: this.config.tabIndex.toString(),
|
|
6197
|
+
'data-readonly': this.readonly ? 'true' : 'false',
|
|
6120
6198
|
});
|
|
6121
6199
|
if (this.config.placeholder !== '') {
|
|
6122
6200
|
this.container.attr('placeholder', this.config.placeholder);
|
|
@@ -6419,7 +6497,6 @@ class Editor {
|
|
|
6419
6497
|
this.root.append(this.containerWrapper);
|
|
6420
6498
|
this.containerWrapper.append(this.container);
|
|
6421
6499
|
this.containerWrapper.append(this.overlayContainer);
|
|
6422
|
-
query(document.body).append(this.popupContainer);
|
|
6423
6500
|
this.togglePlaceholderClass(htmlParser.getHTML());
|
|
6424
6501
|
this.container.append(fragment);
|
|
6425
6502
|
this.unmountPluginMap = Editor.plugin.loadAll(this);
|
|
@@ -6433,9 +6510,7 @@ class Editor {
|
|
|
6433
6510
|
if (this.toolbar) {
|
|
6434
6511
|
this.toolbar.render(this);
|
|
6435
6512
|
}
|
|
6436
|
-
this.root.on('scroll', this.scrollListener);
|
|
6437
6513
|
document.addEventListener('copy', this.copyListener);
|
|
6438
|
-
window.addEventListener('resize', this.resizeListener);
|
|
6439
6514
|
if (!this.readonly) {
|
|
6440
6515
|
document.addEventListener('cut', this.cutListener);
|
|
6441
6516
|
document.addEventListener('paste', this.pasteListener);
|
|
@@ -6472,9 +6547,7 @@ class Editor {
|
|
|
6472
6547
|
this.root.off();
|
|
6473
6548
|
this.root.removeClass('lake-custom-properties');
|
|
6474
6549
|
this.root.empty();
|
|
6475
|
-
this.popupContainer.remove();
|
|
6476
6550
|
document.removeEventListener('copy', this.copyListener);
|
|
6477
|
-
window.removeEventListener('resize', this.resizeListener);
|
|
6478
6551
|
if (!this.readonly) {
|
|
6479
6552
|
document.removeEventListener('cut', this.cutListener);
|
|
6480
6553
|
document.removeEventListener('paste', this.pasteListener);
|
|
@@ -7199,7 +7272,8 @@ class Toolbar {
|
|
|
7199
7272
|
menuWidth: item.menuWidth,
|
|
7200
7273
|
menuHeight: item.menuHeight,
|
|
7201
7274
|
tabIndex: -1,
|
|
7202
|
-
|
|
7275
|
+
location: 'local',
|
|
7276
|
+
direction: this.placement === 'top' ? 'bottom' : 'top',
|
|
7203
7277
|
onSelect: value => {
|
|
7204
7278
|
editor.focus();
|
|
7205
7279
|
item.onSelect(editor, value);
|
|
@@ -7458,7 +7532,6 @@ var codeBlockBox = {
|
|
|
7458
7532
|
const editor = box.getEditor();
|
|
7459
7533
|
const rootNode = query('<div class="lake-code-block" />');
|
|
7460
7534
|
const boxContainer = box.getContainer();
|
|
7461
|
-
boxContainer.css('width', `${editor.container.innerWidth() - 2}px`);
|
|
7462
7535
|
boxContainer.empty();
|
|
7463
7536
|
boxContainer.append(rootNode);
|
|
7464
7537
|
const codeBlockNativeNode = rootNode.get(0);
|
|
@@ -7534,6 +7607,7 @@ var codeBlockBox = {
|
|
|
7534
7607
|
downIcon: icons.get('down'),
|
|
7535
7608
|
defaultValue: langItem ? boxValue.lang : codeBlockConfig.defaultLang,
|
|
7536
7609
|
tooltip: editor.locale.codeBlock.langType(),
|
|
7610
|
+
location: 'global',
|
|
7537
7611
|
menuType: 'list',
|
|
7538
7612
|
menuHeight: '200px',
|
|
7539
7613
|
menuItems: langItems.map((item) => ({
|
|
@@ -7551,10 +7625,6 @@ var codeBlockBox = {
|
|
|
7551
7625
|
},
|
|
7552
7626
|
});
|
|
7553
7627
|
dropdown.render();
|
|
7554
|
-
const resizeListener = () => {
|
|
7555
|
-
boxContainer.css('width', `${editor.container.innerWidth() - 2}px`);
|
|
7556
|
-
};
|
|
7557
|
-
editor.event.on('resize', resizeListener);
|
|
7558
7628
|
rootNode.on('click', () => {
|
|
7559
7629
|
if (codeEditor.hasFocus) {
|
|
7560
7630
|
return;
|
|
@@ -7564,7 +7634,6 @@ var codeBlockBox = {
|
|
|
7564
7634
|
box.event.on('beforeunmount', () => {
|
|
7565
7635
|
dropdown.unmount();
|
|
7566
7636
|
codeEditor.destroy();
|
|
7567
|
-
editor.event.off('resize', resizeListener);
|
|
7568
7637
|
debug('CodeMirror destroyed');
|
|
7569
7638
|
});
|
|
7570
7639
|
},
|
|
@@ -7847,8 +7916,12 @@ function renderError$1(rootNode, box) {
|
|
|
7847
7916
|
function renderUploading(rootNode, box) {
|
|
7848
7917
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7849
7918
|
const editor = box.getEditor();
|
|
7919
|
+
const boxContainer = box.getContainer();
|
|
7850
7920
|
const value = box.value;
|
|
7851
7921
|
const imageInfo = yield getImageInfo(value.url);
|
|
7922
|
+
if (!boxContainer.get(0).isConnected) {
|
|
7923
|
+
return;
|
|
7924
|
+
}
|
|
7852
7925
|
if (!imageInfo.width || !imageInfo.height) {
|
|
7853
7926
|
yield renderError$1(rootNode, box);
|
|
7854
7927
|
return;
|
|
@@ -8371,6 +8444,32 @@ var equationBox = {
|
|
|
8371
8444
|
},
|
|
8372
8445
|
};
|
|
8373
8446
|
|
|
8447
|
+
var mentionBox = {
|
|
8448
|
+
type: 'inline',
|
|
8449
|
+
name: 'mention',
|
|
8450
|
+
render: box => {
|
|
8451
|
+
var _a;
|
|
8452
|
+
const editor = box.getEditor();
|
|
8453
|
+
const { getProfileUrl } = editor.config.mention;
|
|
8454
|
+
const value = box.value;
|
|
8455
|
+
const url = getProfileUrl ? getProfileUrl(value) : '#';
|
|
8456
|
+
const boxContainer = box.getContainer();
|
|
8457
|
+
const rootNode = query(safeTemplate `
|
|
8458
|
+
<div class="lake-mention"><a href="${url}">@${(_a = value.nickname) !== null && _a !== void 0 ? _a : value.name}</a></div>
|
|
8459
|
+
`);
|
|
8460
|
+
boxContainer.empty();
|
|
8461
|
+
boxContainer.append(rootNode);
|
|
8462
|
+
rootNode.on('click', () => {
|
|
8463
|
+
editor.selection.selectBox(box);
|
|
8464
|
+
});
|
|
8465
|
+
if (!editor.readonly) {
|
|
8466
|
+
rootNode.find('a').on('click', (event) => {
|
|
8467
|
+
event.preventDefault();
|
|
8468
|
+
});
|
|
8469
|
+
}
|
|
8470
|
+
},
|
|
8471
|
+
};
|
|
8472
|
+
|
|
8374
8473
|
var copy = (editor) => {
|
|
8375
8474
|
editor.event.on('copy', event => {
|
|
8376
8475
|
const range = editor.selection.range;
|
|
@@ -9343,11 +9442,12 @@ var formatPainter = (editor) => {
|
|
|
9343
9442
|
class LinkPopup {
|
|
9344
9443
|
constructor(config) {
|
|
9345
9444
|
this.linkNode = null;
|
|
9346
|
-
this.
|
|
9347
|
-
this.
|
|
9348
|
-
this.
|
|
9445
|
+
this.scrollListener = () => this.position();
|
|
9446
|
+
this.resizeListener = () => this.position();
|
|
9447
|
+
this.config = config || {};
|
|
9448
|
+
this.locale = this.config.locale || i18nObject('en-US');
|
|
9349
9449
|
this.container = query(safeTemplate `
|
|
9350
|
-
<div class="lake-link-popup">
|
|
9450
|
+
<div class="lake-popup lake-link-popup lake-custom-properties">
|
|
9351
9451
|
<div class="lake-row">${this.locale.link.url()}</div>
|
|
9352
9452
|
<div class="lake-row lake-url-row">
|
|
9353
9453
|
<input type="text" name="url" />
|
|
@@ -9545,16 +9645,13 @@ class LinkPopup {
|
|
|
9545
9645
|
this.container.css('top', `${linkY + linkRect.height}px`);
|
|
9546
9646
|
}
|
|
9547
9647
|
}
|
|
9548
|
-
render() {
|
|
9549
|
-
this.appendCopyButton();
|
|
9550
|
-
this.appendOpenButton();
|
|
9551
|
-
this.appendSaveButton();
|
|
9552
|
-
this.appendUnlinkButton();
|
|
9553
|
-
this.root.append(this.container);
|
|
9554
|
-
}
|
|
9555
9648
|
show(linkNode) {
|
|
9556
|
-
if (this.
|
|
9557
|
-
this.
|
|
9649
|
+
if (!this.container.get(0).isConnected) {
|
|
9650
|
+
this.appendCopyButton();
|
|
9651
|
+
this.appendOpenButton();
|
|
9652
|
+
this.appendSaveButton();
|
|
9653
|
+
this.appendUnlinkButton();
|
|
9654
|
+
query(document.body).append(this.container);
|
|
9558
9655
|
}
|
|
9559
9656
|
if (this.linkNode && this.linkNode.get(0) === linkNode.get(0)) {
|
|
9560
9657
|
return;
|
|
@@ -9571,10 +9668,32 @@ class LinkPopup {
|
|
|
9571
9668
|
this.position();
|
|
9572
9669
|
this.container.css('visibility', '');
|
|
9573
9670
|
this.container.find('input[name="url"]').focus();
|
|
9671
|
+
const viewport = linkNode.closestScroller();
|
|
9672
|
+
if (viewport.length > 0) {
|
|
9673
|
+
viewport.on('scroll', this.scrollListener);
|
|
9674
|
+
}
|
|
9675
|
+
window.addEventListener('resize', this.resizeListener);
|
|
9676
|
+
if (this.config.onShow) {
|
|
9677
|
+
this.config.onShow();
|
|
9678
|
+
}
|
|
9574
9679
|
}
|
|
9575
9680
|
hide() {
|
|
9681
|
+
if (this.linkNode) {
|
|
9682
|
+
const viewport = this.linkNode.closestScroller();
|
|
9683
|
+
if (viewport.length > 0) {
|
|
9684
|
+
viewport.off('scroll', this.scrollListener);
|
|
9685
|
+
}
|
|
9686
|
+
}
|
|
9576
9687
|
this.linkNode = null;
|
|
9577
9688
|
this.container.hide();
|
|
9689
|
+
window.removeEventListener('resize', this.resizeListener);
|
|
9690
|
+
if (this.config.onHide) {
|
|
9691
|
+
this.config.onHide();
|
|
9692
|
+
}
|
|
9693
|
+
}
|
|
9694
|
+
unmount() {
|
|
9695
|
+
this.hide();
|
|
9696
|
+
this.container.remove();
|
|
9578
9697
|
}
|
|
9579
9698
|
}
|
|
9580
9699
|
|
|
@@ -9583,7 +9702,6 @@ var link = (editor) => {
|
|
|
9583
9702
|
return;
|
|
9584
9703
|
}
|
|
9585
9704
|
const popup = new LinkPopup({
|
|
9586
|
-
root: editor.popupContainer,
|
|
9587
9705
|
locale: editor.locale,
|
|
9588
9706
|
onSave: node => {
|
|
9589
9707
|
const range = editor.selection.range;
|
|
@@ -9599,12 +9717,12 @@ var link = (editor) => {
|
|
|
9599
9717
|
editor.selection.sync();
|
|
9600
9718
|
editor.history.save();
|
|
9601
9719
|
},
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9720
|
+
onShow: () => {
|
|
9721
|
+
editor.popup = popup;
|
|
9722
|
+
},
|
|
9723
|
+
onHide: () => {
|
|
9724
|
+
editor.popup = null;
|
|
9725
|
+
},
|
|
9608
9726
|
});
|
|
9609
9727
|
editor.event.on('click', (targetNode) => {
|
|
9610
9728
|
if (popup.container.contains(targetNode)) {
|
|
@@ -9636,6 +9754,7 @@ var link = (editor) => {
|
|
|
9636
9754
|
popup.show(linkNode);
|
|
9637
9755
|
},
|
|
9638
9756
|
});
|
|
9757
|
+
return () => popup.unmount();
|
|
9639
9758
|
};
|
|
9640
9759
|
|
|
9641
9760
|
var hr = (editor) => {
|
|
@@ -9827,31 +9946,418 @@ var specialCharacter = (editor) => {
|
|
|
9827
9946
|
});
|
|
9828
9947
|
};
|
|
9829
9948
|
|
|
9830
|
-
const
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
const
|
|
9845
|
-
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
9849
|
-
|
|
9850
|
-
|
|
9851
|
-
|
|
9852
|
-
|
|
9853
|
-
|
|
9854
|
-
|
|
9949
|
+
const emptyCallback$2 = () => { };
|
|
9950
|
+
class Menu {
|
|
9951
|
+
constructor(config) {
|
|
9952
|
+
this.horizontalDirection = 'right';
|
|
9953
|
+
this.verticalDirection = 'bottom';
|
|
9954
|
+
this.range = null;
|
|
9955
|
+
this.noMouseEvent = false;
|
|
9956
|
+
this.keydownListener = (event) => {
|
|
9957
|
+
if (isKeyHotkey('escape', event)) {
|
|
9958
|
+
event.preventDefault();
|
|
9959
|
+
this.hide();
|
|
9960
|
+
return;
|
|
9961
|
+
}
|
|
9962
|
+
const isDownKey = isKeyHotkey('down', event);
|
|
9963
|
+
const isUpKey = isKeyHotkey('up', event);
|
|
9964
|
+
const isEnterKey = isKeyHotkey('enter', event);
|
|
9965
|
+
if (!isDownKey && !isUpKey && !isEnterKey) {
|
|
9966
|
+
return;
|
|
9967
|
+
}
|
|
9968
|
+
const selectedItemNode = this.container.find('.lake-menu-item-selected');
|
|
9969
|
+
if (selectedItemNode.length === 0) {
|
|
9970
|
+
const firstItem = this.container.find('.lake-menu-item').eq(0);
|
|
9971
|
+
scrollToNode(firstItem, {
|
|
9972
|
+
behavior: 'instant',
|
|
9973
|
+
block: 'start',
|
|
9974
|
+
});
|
|
9975
|
+
firstItem.addClass('lake-menu-item-selected');
|
|
9976
|
+
return;
|
|
9977
|
+
}
|
|
9978
|
+
this.noMouseEvent = true;
|
|
9979
|
+
if (isDownKey) {
|
|
9980
|
+
event.preventDefault();
|
|
9981
|
+
let nextItemNode = selectedItemNode.next();
|
|
9982
|
+
if (nextItemNode.length === 0) {
|
|
9983
|
+
nextItemNode = this.container.find('.lake-menu-item').eq(0);
|
|
9984
|
+
}
|
|
9985
|
+
scrollToNode(nextItemNode, {
|
|
9986
|
+
behavior: 'instant',
|
|
9987
|
+
block: 'end',
|
|
9988
|
+
});
|
|
9989
|
+
this.container.find('.lake-menu-item').removeClass('lake-menu-item-selected');
|
|
9990
|
+
nextItemNode.addClass('lake-menu-item-selected');
|
|
9991
|
+
}
|
|
9992
|
+
else if (isUpKey) {
|
|
9993
|
+
event.preventDefault();
|
|
9994
|
+
let prevItemNode = selectedItemNode.prev();
|
|
9995
|
+
if (prevItemNode.length === 0) {
|
|
9996
|
+
const itemNode = this.container.find('.lake-menu-item');
|
|
9997
|
+
prevItemNode = itemNode.eq(itemNode.length - 1);
|
|
9998
|
+
}
|
|
9999
|
+
scrollToNode(prevItemNode, {
|
|
10000
|
+
behavior: 'instant',
|
|
10001
|
+
block: 'start',
|
|
10002
|
+
});
|
|
10003
|
+
this.container.find('.lake-menu-item').removeClass('lake-menu-item-selected');
|
|
10004
|
+
prevItemNode.addClass('lake-menu-item-selected');
|
|
10005
|
+
}
|
|
10006
|
+
else if (isEnterKey) {
|
|
10007
|
+
event.preventDefault();
|
|
10008
|
+
selectedItemNode.emit('click');
|
|
10009
|
+
}
|
|
10010
|
+
window.setTimeout(() => {
|
|
10011
|
+
this.noMouseEvent = false;
|
|
10012
|
+
}, 50);
|
|
10013
|
+
};
|
|
10014
|
+
this.clickListener = event => {
|
|
10015
|
+
const targetNode = new Nodes(event.target);
|
|
10016
|
+
if (!targetNode.get(0).isConnected) {
|
|
10017
|
+
return;
|
|
10018
|
+
}
|
|
10019
|
+
if (this.container.contains(targetNode)) {
|
|
10020
|
+
return;
|
|
10021
|
+
}
|
|
10022
|
+
this.hide();
|
|
10023
|
+
};
|
|
10024
|
+
this.scrollListener = () => this.updatePosition();
|
|
10025
|
+
this.resizeListener = () => this.updatePosition();
|
|
10026
|
+
this.items = config.items;
|
|
10027
|
+
this.onShow = config.onShow || emptyCallback$2;
|
|
10028
|
+
this.onHide = config.onHide || emptyCallback$2;
|
|
10029
|
+
this.container = query('<ul class="lake-popup lake-menu lake-custom-properties" />');
|
|
10030
|
+
}
|
|
10031
|
+
appendItemNode(itemNode) {
|
|
10032
|
+
itemNode.on('mouseenter', () => {
|
|
10033
|
+
if (this.noMouseEvent) {
|
|
10034
|
+
return;
|
|
10035
|
+
}
|
|
10036
|
+
this.container.find('.lake-menu-item').removeClass('lake-menu-item-selected');
|
|
10037
|
+
itemNode.addClass('lake-menu-item-selected');
|
|
10038
|
+
});
|
|
10039
|
+
itemNode.on('mouseleave', () => {
|
|
10040
|
+
if (this.noMouseEvent) {
|
|
10041
|
+
return;
|
|
10042
|
+
}
|
|
10043
|
+
itemNode.removeClass('lake-menu-item-selected');
|
|
10044
|
+
});
|
|
10045
|
+
this.container.append(itemNode);
|
|
10046
|
+
}
|
|
10047
|
+
appendItems(items) {
|
|
10048
|
+
this.container.empty();
|
|
10049
|
+
for (const item of items) {
|
|
10050
|
+
const itemNode = this.getItemNode(item);
|
|
10051
|
+
itemNode.addClass('lake-menu-item');
|
|
10052
|
+
this.appendItemNode(itemNode);
|
|
10053
|
+
}
|
|
10054
|
+
}
|
|
10055
|
+
selectFirstItemNodeIfNeeded() {
|
|
10056
|
+
const selectedItemNode = this.container.find('.lake-menu-item-selected');
|
|
10057
|
+
if (selectedItemNode.length === 0) {
|
|
10058
|
+
this.container.find('.lake-menu-item').eq(0).addClass('lake-menu-item-selected');
|
|
10059
|
+
}
|
|
10060
|
+
}
|
|
10061
|
+
updatePosition(keepDirection = false) {
|
|
10062
|
+
if (!this.range || this.range.isCollapsed) {
|
|
10063
|
+
return;
|
|
10064
|
+
}
|
|
10065
|
+
const rangeRect = this.range.get().getBoundingClientRect();
|
|
10066
|
+
const rangeX = rangeRect.x + window.scrollX;
|
|
10067
|
+
const rangeY = rangeRect.y + window.scrollY;
|
|
10068
|
+
if (!keepDirection) {
|
|
10069
|
+
if (rangeRect.x + this.container.width() > window.innerWidth) {
|
|
10070
|
+
this.horizontalDirection = 'left';
|
|
10071
|
+
}
|
|
10072
|
+
else {
|
|
10073
|
+
this.horizontalDirection = 'right';
|
|
10074
|
+
}
|
|
10075
|
+
if (rangeRect.y + rangeRect.height + this.container.height() > window.innerHeight) {
|
|
10076
|
+
this.verticalDirection = 'top';
|
|
10077
|
+
}
|
|
10078
|
+
else {
|
|
10079
|
+
this.verticalDirection = 'bottom';
|
|
10080
|
+
}
|
|
10081
|
+
}
|
|
10082
|
+
if (this.horizontalDirection === 'left') {
|
|
10083
|
+
this.container.css('left', `${rangeX - this.container.width() + rangeRect.width}px`);
|
|
10084
|
+
}
|
|
10085
|
+
else {
|
|
10086
|
+
this.container.css('left', `${rangeX}px`);
|
|
10087
|
+
}
|
|
10088
|
+
if (this.verticalDirection === 'top') {
|
|
10089
|
+
this.container.css('top', `${rangeY - this.container.height() - 5}px`);
|
|
10090
|
+
}
|
|
10091
|
+
else {
|
|
10092
|
+
this.container.css('top', `${rangeY + rangeRect.height + 5}px`);
|
|
10093
|
+
}
|
|
10094
|
+
}
|
|
10095
|
+
get visible() {
|
|
10096
|
+
return this.container.get(0).isConnected && this.container.computedCSS('display') !== 'none';
|
|
10097
|
+
}
|
|
10098
|
+
update(keyword) {
|
|
10099
|
+
const items = this.search(keyword);
|
|
10100
|
+
if (items.length === 0) {
|
|
10101
|
+
this.hide();
|
|
10102
|
+
return;
|
|
10103
|
+
}
|
|
10104
|
+
this.appendItems(items);
|
|
10105
|
+
this.selectFirstItemNodeIfNeeded();
|
|
10106
|
+
this.updatePosition(true);
|
|
10107
|
+
this.container.css('visibility', '');
|
|
10108
|
+
}
|
|
10109
|
+
show(range, keyword) {
|
|
10110
|
+
if (range.isCollapsed) {
|
|
10111
|
+
return;
|
|
10112
|
+
}
|
|
10113
|
+
if (this.items.length === 0) {
|
|
10114
|
+
return;
|
|
10115
|
+
}
|
|
10116
|
+
if (!this.container.get(0).isConnected) {
|
|
10117
|
+
query(document.body).append(this.container);
|
|
10118
|
+
}
|
|
10119
|
+
// append all items for fixing the container's width
|
|
10120
|
+
this.appendItems(this.items);
|
|
10121
|
+
this.selectFirstItemNodeIfNeeded();
|
|
10122
|
+
this.range = range;
|
|
10123
|
+
this.container.css('visibility', 'hidden');
|
|
10124
|
+
this.container.show();
|
|
10125
|
+
this.container.get(0).scrollTo(0, 0);
|
|
10126
|
+
this.updatePosition();
|
|
10127
|
+
// fix the container's width
|
|
10128
|
+
this.container.css('width', '');
|
|
10129
|
+
this.container.css('width', `${this.container.width()}px`);
|
|
10130
|
+
const viewport = range.commonAncestor.closestScroller();
|
|
10131
|
+
if (viewport.length > 0) {
|
|
10132
|
+
viewport.on('scroll', this.scrollListener);
|
|
10133
|
+
}
|
|
10134
|
+
document.addEventListener('keydown', this.keydownListener, true);
|
|
10135
|
+
document.addEventListener('click', this.clickListener);
|
|
10136
|
+
window.addEventListener('resize', this.resizeListener);
|
|
10137
|
+
if (keyword) {
|
|
10138
|
+
const items = this.search(keyword);
|
|
10139
|
+
if (items.length === 0) {
|
|
10140
|
+
return;
|
|
10141
|
+
}
|
|
10142
|
+
this.appendItems(items);
|
|
10143
|
+
this.selectFirstItemNodeIfNeeded();
|
|
10144
|
+
this.updatePosition(true);
|
|
10145
|
+
}
|
|
10146
|
+
this.container.css('visibility', '');
|
|
10147
|
+
this.onShow();
|
|
10148
|
+
}
|
|
10149
|
+
hide() {
|
|
10150
|
+
if (this.range) {
|
|
10151
|
+
const viewport = this.range.commonAncestor.closestScroller();
|
|
10152
|
+
if (viewport.length > 0) {
|
|
10153
|
+
viewport.off('scroll', this.scrollListener);
|
|
10154
|
+
}
|
|
10155
|
+
}
|
|
10156
|
+
this.range = null;
|
|
10157
|
+
this.container.hide();
|
|
10158
|
+
document.removeEventListener('keydown', this.keydownListener, true);
|
|
10159
|
+
document.removeEventListener('click', this.clickListener);
|
|
10160
|
+
window.removeEventListener('resize', this.resizeListener);
|
|
10161
|
+
this.onHide();
|
|
10162
|
+
}
|
|
10163
|
+
unmount() {
|
|
10164
|
+
this.hide();
|
|
10165
|
+
this.container.remove();
|
|
10166
|
+
}
|
|
10167
|
+
}
|
|
10168
|
+
|
|
10169
|
+
const emptyCallback$1 = () => { };
|
|
10170
|
+
class MentionMenu extends Menu {
|
|
10171
|
+
constructor(config) {
|
|
10172
|
+
super(config);
|
|
10173
|
+
this.onSelect = config.onSelect || emptyCallback$1;
|
|
10174
|
+
this.container.addClass('lake-mention-menu');
|
|
10175
|
+
}
|
|
10176
|
+
getItemNode(item) {
|
|
10177
|
+
var _a;
|
|
10178
|
+
const itemNode = query(safeTemplate `
|
|
10179
|
+
<li>
|
|
10180
|
+
<div class="lake-mention-avatar"></div>
|
|
10181
|
+
<div class="lake-mention-nickname">${(_a = item.nickname) !== null && _a !== void 0 ? _a : item.name}</div>
|
|
10182
|
+
<div class="lake-mention-name">(${item.name})</div>
|
|
10183
|
+
</li>
|
|
10184
|
+
`);
|
|
10185
|
+
const avatarNode = itemNode.find('.lake-mention-avatar');
|
|
10186
|
+
if (item.avatar) {
|
|
10187
|
+
avatarNode.append(item.avatar);
|
|
10188
|
+
}
|
|
10189
|
+
else {
|
|
10190
|
+
avatarNode.remove();
|
|
10191
|
+
}
|
|
10192
|
+
if (!item.nickname) {
|
|
10193
|
+
itemNode.find('.lake-mention-name').remove();
|
|
10194
|
+
}
|
|
10195
|
+
itemNode.on('click', event => this.onSelect(event, item));
|
|
10196
|
+
return itemNode;
|
|
10197
|
+
}
|
|
10198
|
+
search(keyword) {
|
|
10199
|
+
var _a;
|
|
10200
|
+
keyword = keyword.toLowerCase();
|
|
10201
|
+
const items = [];
|
|
10202
|
+
for (const item of this.items) {
|
|
10203
|
+
const nickname = (_a = item.nickname) !== null && _a !== void 0 ? _a : item.name;
|
|
10204
|
+
if (item.name.toLowerCase().indexOf(keyword) >= 0 ||
|
|
10205
|
+
nickname.toLowerCase().indexOf(keyword) >= 0 ||
|
|
10206
|
+
nickname.replace(/\s+/g, '').indexOf(keyword) >= 0) {
|
|
10207
|
+
items.push(item);
|
|
10208
|
+
}
|
|
10209
|
+
}
|
|
10210
|
+
return items;
|
|
10211
|
+
}
|
|
10212
|
+
}
|
|
10213
|
+
|
|
10214
|
+
function getKeyword$1(range) {
|
|
10215
|
+
const targetRange = range.getCharacterRange('@');
|
|
10216
|
+
if (targetRange === null) {
|
|
10217
|
+
return null;
|
|
10218
|
+
}
|
|
10219
|
+
let text = targetRange.startNode.text().slice(targetRange.startOffset + 1, targetRange.endOffset);
|
|
10220
|
+
text = text.replace(/[\u200B\u2060]/g, '');
|
|
10221
|
+
return text;
|
|
10222
|
+
}
|
|
10223
|
+
var mention = (editor) => {
|
|
10224
|
+
editor.setPluginConfig('mention', {
|
|
10225
|
+
requestMethod: 'GET',
|
|
10226
|
+
items: [],
|
|
10227
|
+
getProfileUrl: (value) => `/${value.name}`,
|
|
10228
|
+
});
|
|
10229
|
+
if (editor.readonly) {
|
|
10230
|
+
return;
|
|
10231
|
+
}
|
|
10232
|
+
const { requestAction, requestMethod, items } = editor.config.mention;
|
|
10233
|
+
let menu = null;
|
|
10234
|
+
const selectListener = (event, item) => {
|
|
10235
|
+
if (menu) {
|
|
10236
|
+
menu.hide();
|
|
10237
|
+
}
|
|
10238
|
+
editor.focus();
|
|
10239
|
+
const targetRange = editor.selection.range.getCharacterRange('@');
|
|
10240
|
+
if (targetRange) {
|
|
10241
|
+
targetRange.get().deleteContents();
|
|
10242
|
+
}
|
|
10243
|
+
editor.selection.insertBox('mention', item);
|
|
10244
|
+
editor.history.save();
|
|
10245
|
+
};
|
|
10246
|
+
const showListener = () => {
|
|
10247
|
+
editor.popup = menu;
|
|
10248
|
+
};
|
|
10249
|
+
const hideListener = () => {
|
|
10250
|
+
editor.popup = null;
|
|
10251
|
+
};
|
|
10252
|
+
const showMenu = () => {
|
|
10253
|
+
const range = editor.selection.range;
|
|
10254
|
+
if (!range.isCollapsed) {
|
|
10255
|
+
return;
|
|
10256
|
+
}
|
|
10257
|
+
const targetRange = range.getCharacterRange('@');
|
|
10258
|
+
if (targetRange === null) {
|
|
10259
|
+
return;
|
|
10260
|
+
}
|
|
10261
|
+
const keyword = getKeyword$1(range);
|
|
10262
|
+
if (keyword === null) {
|
|
10263
|
+
return;
|
|
10264
|
+
}
|
|
10265
|
+
if (!menu) {
|
|
10266
|
+
if (requestAction) {
|
|
10267
|
+
request({
|
|
10268
|
+
onSuccess: body => {
|
|
10269
|
+
if (!body.data) {
|
|
10270
|
+
return;
|
|
10271
|
+
}
|
|
10272
|
+
menu = new MentionMenu({
|
|
10273
|
+
items: body.data,
|
|
10274
|
+
onSelect: selectListener,
|
|
10275
|
+
onShow: showListener,
|
|
10276
|
+
onHide: hideListener,
|
|
10277
|
+
});
|
|
10278
|
+
menu.show(targetRange, keyword);
|
|
10279
|
+
},
|
|
10280
|
+
action: requestAction,
|
|
10281
|
+
method: requestMethod,
|
|
10282
|
+
});
|
|
10283
|
+
}
|
|
10284
|
+
else {
|
|
10285
|
+
menu = new MentionMenu({
|
|
10286
|
+
items,
|
|
10287
|
+
onSelect: selectListener,
|
|
10288
|
+
onShow: showListener,
|
|
10289
|
+
onHide: hideListener,
|
|
10290
|
+
});
|
|
10291
|
+
menu.show(targetRange, keyword);
|
|
10292
|
+
}
|
|
10293
|
+
return;
|
|
10294
|
+
}
|
|
10295
|
+
menu.show(targetRange, keyword);
|
|
10296
|
+
};
|
|
10297
|
+
editor.container.on('keyup', event => {
|
|
10298
|
+
if (editor.isComposing) {
|
|
10299
|
+
return;
|
|
10300
|
+
}
|
|
10301
|
+
const keyboardEvent = event;
|
|
10302
|
+
if (isKeyHotkey(['down', 'up', 'enter'], keyboardEvent)) {
|
|
10303
|
+
return;
|
|
10304
|
+
}
|
|
10305
|
+
if (!menu || !menu.visible) {
|
|
10306
|
+
if (keyboardEvent.key === '@') {
|
|
10307
|
+
showMenu();
|
|
10308
|
+
return;
|
|
10309
|
+
}
|
|
10310
|
+
if (isKeyHotkey(['backspace', 'delete'], keyboardEvent)) {
|
|
10311
|
+
showMenu();
|
|
10312
|
+
}
|
|
10313
|
+
else {
|
|
10314
|
+
return;
|
|
10315
|
+
}
|
|
10316
|
+
}
|
|
10317
|
+
const range = editor.selection.range;
|
|
10318
|
+
const keyword = getKeyword$1(range);
|
|
10319
|
+
if (keyword === null) {
|
|
10320
|
+
if (menu) {
|
|
10321
|
+
menu.hide();
|
|
10322
|
+
}
|
|
10323
|
+
return;
|
|
10324
|
+
}
|
|
10325
|
+
if (menu) {
|
|
10326
|
+
menu.update(keyword);
|
|
10327
|
+
}
|
|
10328
|
+
});
|
|
10329
|
+
return () => {
|
|
10330
|
+
if (menu) {
|
|
10331
|
+
menu.unmount();
|
|
10332
|
+
}
|
|
10333
|
+
};
|
|
10334
|
+
};
|
|
10335
|
+
|
|
10336
|
+
const headingTypeMap = new Map([
|
|
10337
|
+
['#', 'h1'],
|
|
10338
|
+
['##', 'h2'],
|
|
10339
|
+
['###', 'h3'],
|
|
10340
|
+
['####', 'h4'],
|
|
10341
|
+
['#####', 'h5'],
|
|
10342
|
+
['######', 'h6'],
|
|
10343
|
+
]);
|
|
10344
|
+
const shortLangTypeMap = new Map([
|
|
10345
|
+
['js', 'javascript'],
|
|
10346
|
+
['ts', 'typescript'],
|
|
10347
|
+
['md', 'markdown'],
|
|
10348
|
+
['htm', 'html'],
|
|
10349
|
+
]);
|
|
10350
|
+
const markItemList = [
|
|
10351
|
+
{
|
|
10352
|
+
re: /\*\*(.+?)\*\*$/,
|
|
10353
|
+
getParameters: () => [
|
|
10354
|
+
'bold',
|
|
10355
|
+
],
|
|
10356
|
+
},
|
|
10357
|
+
{
|
|
10358
|
+
re: /__(.+?)__$/,
|
|
10359
|
+
getParameters: () => [
|
|
10360
|
+
'bold',
|
|
9855
10361
|
],
|
|
9856
10362
|
},
|
|
9857
10363
|
{
|
|
@@ -10947,87 +11453,17 @@ const slashItems = [
|
|
|
10947
11453
|
},
|
|
10948
11454
|
];
|
|
10949
11455
|
|
|
11456
|
+
const emptyCallback = () => { };
|
|
10950
11457
|
const slashItemMap = new Map();
|
|
10951
11458
|
for (const item of slashItems) {
|
|
10952
11459
|
slashItemMap.set(item.name, item);
|
|
10953
11460
|
}
|
|
10954
|
-
class
|
|
11461
|
+
class SlashMenu extends Menu {
|
|
10955
11462
|
constructor(config) {
|
|
10956
|
-
|
|
10957
|
-
this.
|
|
10958
|
-
this.
|
|
10959
|
-
this.
|
|
10960
|
-
this.verticalDirection = 'bottom';
|
|
10961
|
-
this.keydownListener = (event) => {
|
|
10962
|
-
if (isKeyHotkey('escape', event)) {
|
|
10963
|
-
event.preventDefault();
|
|
10964
|
-
this.hide();
|
|
10965
|
-
return;
|
|
10966
|
-
}
|
|
10967
|
-
const isDownKey = isKeyHotkey('down', event);
|
|
10968
|
-
const isUpKey = isKeyHotkey('up', event);
|
|
10969
|
-
const isEnterKey = isKeyHotkey('enter', event);
|
|
10970
|
-
if (!isDownKey && !isUpKey && !isEnterKey) {
|
|
10971
|
-
return;
|
|
10972
|
-
}
|
|
10973
|
-
const selectedItemNode = this.container.find('.lake-slash-item-selected');
|
|
10974
|
-
if (selectedItemNode.length === 0) {
|
|
10975
|
-
const firstItem = this.container.find('.lake-slash-item').eq(0);
|
|
10976
|
-
scrollToNode(firstItem, {
|
|
10977
|
-
behavior: 'instant',
|
|
10978
|
-
block: 'start',
|
|
10979
|
-
});
|
|
10980
|
-
firstItem.addClass('lake-slash-item-selected');
|
|
10981
|
-
return;
|
|
10982
|
-
}
|
|
10983
|
-
this.noMouseEvent = true;
|
|
10984
|
-
if (isDownKey) {
|
|
10985
|
-
event.preventDefault();
|
|
10986
|
-
let nextItemNode = selectedItemNode.next();
|
|
10987
|
-
if (nextItemNode.length === 0) {
|
|
10988
|
-
nextItemNode = this.container.find('.lake-slash-item').eq(0);
|
|
10989
|
-
}
|
|
10990
|
-
scrollToNode(nextItemNode, {
|
|
10991
|
-
behavior: 'instant',
|
|
10992
|
-
block: 'end',
|
|
10993
|
-
});
|
|
10994
|
-
this.container.find('.lake-slash-item').removeClass('lake-slash-item-selected');
|
|
10995
|
-
nextItemNode.addClass('lake-slash-item-selected');
|
|
10996
|
-
}
|
|
10997
|
-
else if (isUpKey) {
|
|
10998
|
-
event.preventDefault();
|
|
10999
|
-
let prevItemNode = selectedItemNode.prev();
|
|
11000
|
-
if (prevItemNode.length === 0) {
|
|
11001
|
-
const itemNode = this.container.find('.lake-slash-item');
|
|
11002
|
-
prevItemNode = itemNode.eq(itemNode.length - 1);
|
|
11003
|
-
}
|
|
11004
|
-
scrollToNode(prevItemNode, {
|
|
11005
|
-
behavior: 'instant',
|
|
11006
|
-
block: 'start',
|
|
11007
|
-
});
|
|
11008
|
-
this.container.find('.lake-slash-item').removeClass('lake-slash-item-selected');
|
|
11009
|
-
prevItemNode.addClass('lake-slash-item-selected');
|
|
11010
|
-
}
|
|
11011
|
-
else if (isEnterKey) {
|
|
11012
|
-
event.preventDefault();
|
|
11013
|
-
selectedItemNode.emit('click');
|
|
11014
|
-
}
|
|
11015
|
-
window.setTimeout(() => {
|
|
11016
|
-
this.noMouseEvent = false;
|
|
11017
|
-
}, 50);
|
|
11018
|
-
};
|
|
11019
|
-
this.clickListener = (targetNode) => {
|
|
11020
|
-
if (this.container.contains(targetNode)) {
|
|
11021
|
-
return;
|
|
11022
|
-
}
|
|
11023
|
-
this.hide();
|
|
11024
|
-
};
|
|
11025
|
-
this.scrollListener = () => this.position();
|
|
11026
|
-
this.resizeListener = () => this.position();
|
|
11027
|
-
this.editor = config.editor;
|
|
11028
|
-
this.items = config.items;
|
|
11029
|
-
this.root = config.editor.popupContainer;
|
|
11030
|
-
this.container = query('<ul class="lake-slash-popup" />');
|
|
11463
|
+
super(config);
|
|
11464
|
+
this.locale = config.locale || i18nObject('en-US');
|
|
11465
|
+
this.onSelect = config.onSelect || emptyCallback;
|
|
11466
|
+
this.container.addClass('lake-slash-menu');
|
|
11031
11467
|
}
|
|
11032
11468
|
getItem(name) {
|
|
11033
11469
|
if (typeof name !== 'string') {
|
|
@@ -11039,20 +11475,12 @@ class SlashPopup {
|
|
|
11039
11475
|
}
|
|
11040
11476
|
return item;
|
|
11041
11477
|
}
|
|
11042
|
-
|
|
11043
|
-
const
|
|
11044
|
-
const
|
|
11045
|
-
this.
|
|
11046
|
-
block.empty();
|
|
11047
|
-
appendBreak(block);
|
|
11048
|
-
range.shrinkBefore(block);
|
|
11049
|
-
}
|
|
11050
|
-
appendItem(item) {
|
|
11051
|
-
const editor = this.editor;
|
|
11052
|
-
const itemTitle = typeof item.title === 'string' ? item.title : item.title(editor.locale);
|
|
11053
|
-
const itemDescription = typeof item.description === 'string' ? item.description : item.description(editor.locale);
|
|
11478
|
+
getItemNode(name) {
|
|
11479
|
+
const item = this.getItem(name);
|
|
11480
|
+
const itemTitle = typeof item.title === 'string' ? item.title : item.title(this.locale);
|
|
11481
|
+
const itemDescription = typeof item.description === 'string' ? item.description : item.description(this.locale);
|
|
11054
11482
|
const itemNode = query(safeTemplate `
|
|
11055
|
-
<li
|
|
11483
|
+
<li name="${item.name}">
|
|
11056
11484
|
<div class="lake-slash-icon"></div>
|
|
11057
11485
|
<div class="lake-slash-text">
|
|
11058
11486
|
<div class="lake-slash-title">${itemTitle}</div>
|
|
@@ -11064,20 +11492,6 @@ class SlashPopup {
|
|
|
11064
11492
|
if (icon) {
|
|
11065
11493
|
itemNode.find('.lake-slash-icon').append(icon);
|
|
11066
11494
|
}
|
|
11067
|
-
this.container.append(itemNode);
|
|
11068
|
-
itemNode.on('mouseenter', () => {
|
|
11069
|
-
if (this.noMouseEvent) {
|
|
11070
|
-
return;
|
|
11071
|
-
}
|
|
11072
|
-
this.container.find('.lake-slash-item').removeClass('lake-slash-item-selected');
|
|
11073
|
-
itemNode.addClass('lake-slash-item-selected');
|
|
11074
|
-
});
|
|
11075
|
-
itemNode.on('mouseleave', () => {
|
|
11076
|
-
if (this.noMouseEvent) {
|
|
11077
|
-
return;
|
|
11078
|
-
}
|
|
11079
|
-
itemNode.removeClass('lake-slash-item-selected');
|
|
11080
|
-
});
|
|
11081
11495
|
if (item.type === 'upload') {
|
|
11082
11496
|
itemNode.append('<input type="file" />');
|
|
11083
11497
|
const fileNode = itemNode.find('input[type="file"]');
|
|
@@ -11089,49 +11503,21 @@ class SlashPopup {
|
|
|
11089
11503
|
fileNode.attr('multiple', 'true');
|
|
11090
11504
|
}
|
|
11091
11505
|
fileNode.on('click', event => event.stopPropagation());
|
|
11092
|
-
fileNode.on('change', event =>
|
|
11093
|
-
|
|
11094
|
-
this.emptyBlock();
|
|
11095
|
-
const target = event.target;
|
|
11096
|
-
const files = target.files || [];
|
|
11097
|
-
for (const file of files) {
|
|
11098
|
-
uploadFile({
|
|
11099
|
-
editor,
|
|
11100
|
-
name: item.name,
|
|
11101
|
-
file,
|
|
11102
|
-
onError: error => {
|
|
11103
|
-
fileNativeNode.value = '';
|
|
11104
|
-
editor.config.onMessage('error', error);
|
|
11105
|
-
},
|
|
11106
|
-
onSuccess: () => {
|
|
11107
|
-
fileNativeNode.value = '';
|
|
11108
|
-
},
|
|
11109
|
-
});
|
|
11110
|
-
}
|
|
11111
|
-
});
|
|
11112
|
-
itemNode.on('click', () => {
|
|
11113
|
-
fileNativeNode.click();
|
|
11114
|
-
});
|
|
11506
|
+
fileNode.on('change', event => this.onSelect(event, item, fileNode));
|
|
11507
|
+
itemNode.on('click', () => fileNativeNode.click());
|
|
11115
11508
|
}
|
|
11116
11509
|
else {
|
|
11117
|
-
itemNode.on('click',
|
|
11118
|
-
editor.focus();
|
|
11119
|
-
this.emptyBlock();
|
|
11120
|
-
item.onClick(editor, item.name);
|
|
11121
|
-
});
|
|
11510
|
+
itemNode.on('click', event => this.onSelect(event, item));
|
|
11122
11511
|
}
|
|
11123
|
-
|
|
11124
|
-
get visible() {
|
|
11125
|
-
return this.container.get(0).isConnected && this.container.computedCSS('display') !== 'none';
|
|
11512
|
+
return itemNode;
|
|
11126
11513
|
}
|
|
11127
11514
|
search(keyword) {
|
|
11128
|
-
const editor = this.editor;
|
|
11129
11515
|
const localeEnglish = i18nObject('en-US');
|
|
11130
11516
|
keyword = keyword.toLowerCase();
|
|
11131
11517
|
const items = [];
|
|
11132
11518
|
for (const name of this.items) {
|
|
11133
11519
|
const item = this.getItem(name);
|
|
11134
|
-
let itemTitle = typeof item.title === 'string' ? item.title : item.title(
|
|
11520
|
+
let itemTitle = typeof item.title === 'string' ? item.title : item.title(this.locale);
|
|
11135
11521
|
itemTitle = itemTitle.toLowerCase();
|
|
11136
11522
|
let itemTitleEnglish = typeof item.title === 'string' ? item.title : item.title(localeEnglish);
|
|
11137
11523
|
itemTitleEnglish = itemTitleEnglish.toLowerCase();
|
|
@@ -11144,103 +11530,6 @@ class SlashPopup {
|
|
|
11144
11530
|
}
|
|
11145
11531
|
return items;
|
|
11146
11532
|
}
|
|
11147
|
-
position(keepDirection = false) {
|
|
11148
|
-
if (!this.range) {
|
|
11149
|
-
return;
|
|
11150
|
-
}
|
|
11151
|
-
this.container.css('visibility', '');
|
|
11152
|
-
const rangeRect = this.range.get().getBoundingClientRect();
|
|
11153
|
-
const rangeX = rangeRect.x + window.scrollX;
|
|
11154
|
-
const rangeY = rangeRect.y + window.scrollY;
|
|
11155
|
-
if (!keepDirection) {
|
|
11156
|
-
if (rangeRect.x + this.container.width() > window.innerWidth) {
|
|
11157
|
-
this.horizontalDirection = 'left';
|
|
11158
|
-
}
|
|
11159
|
-
else {
|
|
11160
|
-
this.horizontalDirection = 'right';
|
|
11161
|
-
}
|
|
11162
|
-
if (rangeRect.y + rangeRect.height + this.container.height() > window.innerHeight) {
|
|
11163
|
-
this.verticalDirection = 'top';
|
|
11164
|
-
}
|
|
11165
|
-
else {
|
|
11166
|
-
this.verticalDirection = 'bottom';
|
|
11167
|
-
}
|
|
11168
|
-
}
|
|
11169
|
-
if (this.horizontalDirection === 'left') {
|
|
11170
|
-
this.container.css('left', `${rangeX - this.container.width() + rangeRect.width}px`);
|
|
11171
|
-
}
|
|
11172
|
-
else {
|
|
11173
|
-
this.container.css('left', `${rangeX}px`);
|
|
11174
|
-
}
|
|
11175
|
-
if (this.verticalDirection === 'top') {
|
|
11176
|
-
this.container.css('top', `${rangeY - this.container.height() - 5}px`);
|
|
11177
|
-
}
|
|
11178
|
-
else {
|
|
11179
|
-
this.container.css('top', `${rangeY + rangeRect.height + 5}px`);
|
|
11180
|
-
}
|
|
11181
|
-
}
|
|
11182
|
-
render() {
|
|
11183
|
-
this.root.append(this.container);
|
|
11184
|
-
this.update();
|
|
11185
|
-
}
|
|
11186
|
-
update(keyword = null) {
|
|
11187
|
-
if (keyword !== null && this.keyword === keyword) {
|
|
11188
|
-
return;
|
|
11189
|
-
}
|
|
11190
|
-
const items = keyword !== null ? this.search(keyword) : this.items;
|
|
11191
|
-
if (items.length === 0) {
|
|
11192
|
-
this.hide();
|
|
11193
|
-
return;
|
|
11194
|
-
}
|
|
11195
|
-
this.keyword = keyword;
|
|
11196
|
-
this.container.empty();
|
|
11197
|
-
for (const name of items) {
|
|
11198
|
-
const item = this.getItem(name);
|
|
11199
|
-
this.appendItem(item);
|
|
11200
|
-
}
|
|
11201
|
-
const selectedItemNode = this.container.find('.lake-slash-item-selected');
|
|
11202
|
-
if (selectedItemNode.length === 0) {
|
|
11203
|
-
this.container.find('.lake-slash-item').eq(0).addClass('lake-slash-item-selected');
|
|
11204
|
-
}
|
|
11205
|
-
this.position(true);
|
|
11206
|
-
}
|
|
11207
|
-
show(range, keyword) {
|
|
11208
|
-
const editor = this.editor;
|
|
11209
|
-
if (this.root.find('.lake-slash-popup').length === 0) {
|
|
11210
|
-
this.render();
|
|
11211
|
-
}
|
|
11212
|
-
else {
|
|
11213
|
-
this.update();
|
|
11214
|
-
}
|
|
11215
|
-
this.range = range;
|
|
11216
|
-
this.container.css('visibility', 'hidden');
|
|
11217
|
-
this.container.show();
|
|
11218
|
-
this.position();
|
|
11219
|
-
// for fixing the container's width
|
|
11220
|
-
this.container.css('width', '');
|
|
11221
|
-
this.container.css('width', `${this.container.width()}px`);
|
|
11222
|
-
if (keyword) {
|
|
11223
|
-
this.update(keyword);
|
|
11224
|
-
}
|
|
11225
|
-
this.container.css('visibility', '');
|
|
11226
|
-
document.addEventListener('keydown', this.keydownListener, true);
|
|
11227
|
-
editor.event.on('click', this.clickListener);
|
|
11228
|
-
editor.event.on('scroll', this.scrollListener);
|
|
11229
|
-
editor.event.on('resize', this.resizeListener);
|
|
11230
|
-
}
|
|
11231
|
-
hide() {
|
|
11232
|
-
const editor = this.editor;
|
|
11233
|
-
this.range = null;
|
|
11234
|
-
this.container.hide();
|
|
11235
|
-
document.removeEventListener('keydown', this.keydownListener, true);
|
|
11236
|
-
editor.event.off('click', this.clickListener);
|
|
11237
|
-
editor.event.off('scroll', this.scrollListener);
|
|
11238
|
-
editor.event.off('resize', this.resizeListener);
|
|
11239
|
-
}
|
|
11240
|
-
unmount() {
|
|
11241
|
-
this.hide();
|
|
11242
|
-
this.container.remove();
|
|
11243
|
-
}
|
|
11244
11533
|
}
|
|
11245
11534
|
|
|
11246
11535
|
const defaultItems = [
|
|
@@ -11265,25 +11554,12 @@ function getKeyword(block) {
|
|
|
11265
11554
|
}
|
|
11266
11555
|
return text.substring(1);
|
|
11267
11556
|
}
|
|
11268
|
-
function
|
|
11557
|
+
function emptyBlock(editor) {
|
|
11269
11558
|
const range = editor.selection.range;
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
|
|
11274
|
-
if (!block) {
|
|
11275
|
-
return;
|
|
11276
|
-
}
|
|
11277
|
-
if (block.find('lake-box').length > 0) {
|
|
11278
|
-
return;
|
|
11279
|
-
}
|
|
11280
|
-
const keyword = getKeyword(block);
|
|
11281
|
-
if (keyword === null) {
|
|
11282
|
-
return;
|
|
11283
|
-
}
|
|
11284
|
-
const slashRange = range.clone();
|
|
11285
|
-
slashRange.selectNodeContents(block);
|
|
11286
|
-
popup.show(slashRange, keyword);
|
|
11559
|
+
const block = range.commonAncestor.closestBlock();
|
|
11560
|
+
block.empty();
|
|
11561
|
+
appendBreak(block);
|
|
11562
|
+
range.shrinkBefore(block);
|
|
11287
11563
|
}
|
|
11288
11564
|
var slash = (editor) => {
|
|
11289
11565
|
editor.setPluginConfig('slash', {
|
|
@@ -11292,10 +11568,68 @@ var slash = (editor) => {
|
|
|
11292
11568
|
if (editor.readonly) {
|
|
11293
11569
|
return;
|
|
11294
11570
|
}
|
|
11295
|
-
const
|
|
11296
|
-
editor,
|
|
11571
|
+
const menu = new SlashMenu({
|
|
11572
|
+
locale: editor.locale,
|
|
11297
11573
|
items: editor.config.slash.items,
|
|
11574
|
+
onSelect: (event, item, fileNode) => {
|
|
11575
|
+
if (menu) {
|
|
11576
|
+
menu.hide();
|
|
11577
|
+
}
|
|
11578
|
+
editor.focus();
|
|
11579
|
+
emptyBlock(editor);
|
|
11580
|
+
if (item.type === 'upload') {
|
|
11581
|
+
if (!fileNode) {
|
|
11582
|
+
return;
|
|
11583
|
+
}
|
|
11584
|
+
const target = event.target;
|
|
11585
|
+
const fileNativeNode = fileNode.get(0);
|
|
11586
|
+
const files = target.files || [];
|
|
11587
|
+
for (const file of files) {
|
|
11588
|
+
uploadFile({
|
|
11589
|
+
editor,
|
|
11590
|
+
name: item.name,
|
|
11591
|
+
file,
|
|
11592
|
+
onError: error => {
|
|
11593
|
+
fileNativeNode.value = '';
|
|
11594
|
+
editor.config.onMessage('error', error);
|
|
11595
|
+
},
|
|
11596
|
+
onSuccess: () => {
|
|
11597
|
+
fileNativeNode.value = '';
|
|
11598
|
+
},
|
|
11599
|
+
});
|
|
11600
|
+
}
|
|
11601
|
+
}
|
|
11602
|
+
else {
|
|
11603
|
+
item.onClick(editor, item.name);
|
|
11604
|
+
}
|
|
11605
|
+
},
|
|
11606
|
+
onShow: () => {
|
|
11607
|
+
editor.popup = menu;
|
|
11608
|
+
},
|
|
11609
|
+
onHide: () => {
|
|
11610
|
+
editor.popup = null;
|
|
11611
|
+
},
|
|
11298
11612
|
});
|
|
11613
|
+
const showMenu = () => {
|
|
11614
|
+
const range = editor.selection.range;
|
|
11615
|
+
if (!range.isCollapsed) {
|
|
11616
|
+
return;
|
|
11617
|
+
}
|
|
11618
|
+
const block = range.getBlocks()[0];
|
|
11619
|
+
if (!block) {
|
|
11620
|
+
return;
|
|
11621
|
+
}
|
|
11622
|
+
if (block.find('lake-box').length > 0) {
|
|
11623
|
+
return;
|
|
11624
|
+
}
|
|
11625
|
+
const keyword = getKeyword(block);
|
|
11626
|
+
if (keyword === null) {
|
|
11627
|
+
return;
|
|
11628
|
+
}
|
|
11629
|
+
const slashRange = range.clone();
|
|
11630
|
+
slashRange.selectNodeContents(block);
|
|
11631
|
+
menu.show(slashRange, keyword);
|
|
11632
|
+
};
|
|
11299
11633
|
editor.container.on('keyup', event => {
|
|
11300
11634
|
if (editor.isComposing) {
|
|
11301
11635
|
return;
|
|
@@ -11304,13 +11638,13 @@ var slash = (editor) => {
|
|
|
11304
11638
|
if (isKeyHotkey(['down', 'up', 'enter'], keyboardEvent)) {
|
|
11305
11639
|
return;
|
|
11306
11640
|
}
|
|
11307
|
-
if (!
|
|
11641
|
+
if (!menu.visible) {
|
|
11308
11642
|
if (isKeyHotkey('/', keyboardEvent)) {
|
|
11309
|
-
|
|
11643
|
+
showMenu();
|
|
11310
11644
|
return;
|
|
11311
11645
|
}
|
|
11312
11646
|
if (isKeyHotkey(['backspace', 'delete'], keyboardEvent)) {
|
|
11313
|
-
|
|
11647
|
+
showMenu();
|
|
11314
11648
|
}
|
|
11315
11649
|
else {
|
|
11316
11650
|
return;
|
|
@@ -11323,12 +11657,14 @@ var slash = (editor) => {
|
|
|
11323
11657
|
}
|
|
11324
11658
|
const keyword = getKeyword(block);
|
|
11325
11659
|
if (keyword === null) {
|
|
11326
|
-
|
|
11660
|
+
menu.hide();
|
|
11327
11661
|
return;
|
|
11328
11662
|
}
|
|
11329
|
-
|
|
11663
|
+
menu.update(keyword);
|
|
11330
11664
|
});
|
|
11331
|
-
return () =>
|
|
11665
|
+
return () => {
|
|
11666
|
+
menu.unmount();
|
|
11667
|
+
};
|
|
11332
11668
|
};
|
|
11333
11669
|
|
|
11334
11670
|
Editor.box.add(hrBox);
|
|
@@ -11338,6 +11674,7 @@ Editor.box.add(videoBox);
|
|
|
11338
11674
|
Editor.box.add(fileBox);
|
|
11339
11675
|
Editor.box.add(emojiBox);
|
|
11340
11676
|
Editor.box.add(equationBox);
|
|
11677
|
+
Editor.box.add(mentionBox);
|
|
11341
11678
|
Editor.plugin.add('copy', copy);
|
|
11342
11679
|
Editor.plugin.add('cut', cut);
|
|
11343
11680
|
Editor.plugin.add('paste', paste);
|
|
@@ -11372,6 +11709,7 @@ Editor.plugin.add('file', file);
|
|
|
11372
11709
|
Editor.plugin.add('emoji', emoji);
|
|
11373
11710
|
Editor.plugin.add('equation', equation);
|
|
11374
11711
|
Editor.plugin.add('specialCharacter', specialCharacter);
|
|
11712
|
+
Editor.plugin.add('mention', mention);
|
|
11375
11713
|
Editor.plugin.add('markdown', markdown);
|
|
11376
11714
|
Editor.plugin.add('enterKey', enterKey);
|
|
11377
11715
|
Editor.plugin.add('shiftEnterKey', shiftEnterKey);
|