@zipify/wysiwyg 2.4.1 → 2.4.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/cli.js +1 -1
- package/dist/wysiwyg.css +4 -4
- package/dist/wysiwyg.mjs +42 -17
- package/example/fonts.js +0 -7
- package/lib/components/toolbar/controls/link/LinkControl.vue +11 -5
- package/lib/components/toolbar/controls/link/composables/__tests__/useLink.test.js +32 -0
- package/lib/components/toolbar/controls/link/composables/useLink.js +8 -3
- package/lib/extensions/FontStyle.js +8 -3
- package/lib/extensions/__tests__/FontFamily.test.js +3 -1
- package/lib/models/Font.js +10 -3
- package/lib/models/__tests__/Font.test.js +19 -1
- package/lib/regExps.js +6 -0
- package/package.json +1 -1
package/dist/wysiwyg.css
CHANGED
|
@@ -632,17 +632,17 @@
|
|
|
632
632
|
color: rgb(var(--zw-color-white));
|
|
633
633
|
}
|
|
634
634
|
|
|
635
|
-
.zw-link-modal[data-v-
|
|
635
|
+
.zw-link-modal[data-v-eea2f92a] {
|
|
636
636
|
width: 266px;
|
|
637
637
|
}
|
|
638
|
-
.zw-link-modal__body[data-v-
|
|
638
|
+
.zw-link-modal__body[data-v-eea2f92a] {
|
|
639
639
|
padding: var(--zw-offset-sm);
|
|
640
640
|
}
|
|
641
|
-
.zw-link-modal__actions[data-v-
|
|
641
|
+
.zw-link-modal__actions[data-v-eea2f92a] {
|
|
642
642
|
display: flex;
|
|
643
643
|
justify-content: flex-end;
|
|
644
644
|
}
|
|
645
|
-
[data-v-
|
|
645
|
+
[data-v-eea2f92a] .zw-link-modal-dropdown__option {
|
|
646
646
|
width: 234px;
|
|
647
647
|
}
|
|
648
648
|
|
package/dist/wysiwyg.mjs
CHANGED
|
@@ -26,7 +26,7 @@ var __privateMethod = (obj, member, method) => {
|
|
|
26
26
|
__accessCheck(obj, member, "access private method");
|
|
27
27
|
return method;
|
|
28
28
|
};
|
|
29
|
-
var _domParser, _parser, _NodeFilter, NodeFilter_get, _Node, Node_get, _removeComments, removeComments_fn, _normalizeRootTags, normalizeRootTags_fn, _createNodeIterator, createNodeIterator_fn, _iterateNodes, iterateNodes_fn, _runIterator, runIterator_fn, _removeEmptyNodes, removeEmptyNodes_fn, _normalizeListItems, normalizeListItems_fn, _isBlockNode, isBlockNode_fn, _isRootNode, isRootNode_fn, _assignElementProperties, assignElementProperties_fn, _removeStyleProperties, removeStyleProperties_fn, _normalizeBreakLines, normalizeBreakLines_fn, _normalizeBlockTextDecoration, normalizeBlockTextDecoration_fn, _moveTextDecorationToChildren, moveTextDecorationToChildren_fn, _parseTextDecoration, parseTextDecoration_fn, _normalizeBlockBackgroundColor, normalizeBlockBackgroundColor_fn, _moveBackgroundColorToChildren, moveBackgroundColorToChildren_fn, _wrapTextNode, wrapTextNode_fn, _iterateNodes2, iterateNodes_fn2, _iterateChildNodes, iterateChildNodes_fn, _bubbleMarks, bubbleMarks_fn, _canBubbleMark, canBubbleMark_fn, _includesMark, includesMark_fn, _includesMarkType, includesMarkType_fn, _removeMark, removeMark_fn, _addMark, addMark_fn, _findMarkIndexByType, findMarkIndexByType_fn, _buildHtml, buildHtml_fn, _buildJson, buildJson_fn, _textBlock, textBlock_fn, _normalizeTextBlockArgs, normalizeTextBlockArgs_fn, _buildDecorations, buildDecorations_fn;
|
|
29
|
+
var _domParser, _parser, _NodeFilter, NodeFilter_get, _Node, Node_get, _removeComments, removeComments_fn, _normalizeRootTags, normalizeRootTags_fn, _createNodeIterator, createNodeIterator_fn, _iterateNodes, iterateNodes_fn, _runIterator, runIterator_fn, _removeEmptyNodes, removeEmptyNodes_fn, _normalizeListItems, normalizeListItems_fn, _isBlockNode, isBlockNode_fn, _isRootNode, isRootNode_fn, _assignElementProperties, assignElementProperties_fn, _removeStyleProperties, removeStyleProperties_fn, _normalizeBreakLines, normalizeBreakLines_fn, _normalizeBlockTextDecoration, normalizeBlockTextDecoration_fn, _moveTextDecorationToChildren, moveTextDecorationToChildren_fn, _parseTextDecoration, parseTextDecoration_fn, _normalizeBlockBackgroundColor, normalizeBlockBackgroundColor_fn, _moveBackgroundColorToChildren, moveBackgroundColorToChildren_fn, _wrapTextNode, wrapTextNode_fn, _iterateNodes2, iterateNodes_fn2, _iterateChildNodes, iterateChildNodes_fn, _bubbleMarks, bubbleMarks_fn, _canBubbleMark, canBubbleMark_fn, _includesMark, includesMark_fn, _includesMarkType, includesMarkType_fn, _removeMark, removeMark_fn, _addMark, addMark_fn, _findMarkIndexByType, findMarkIndexByType_fn, _buildHtml, buildHtml_fn, _buildJson, buildJson_fn, _textBlock, textBlock_fn, _normalizeTextBlockArgs, normalizeTextBlockArgs_fn, _buildDecorations, buildDecorations_fn, _getWeights, getWeights_fn;
|
|
30
30
|
import { computed, ref, watch, inject, onUnmounted, nextTick, provide, onMounted, toRef, unref, reactive } from "vue";
|
|
31
31
|
import { ColorModel, ZipifyColorPicker } from "@zipify/colorpicker";
|
|
32
32
|
function OrderedMap(content) {
|
|
@@ -23703,6 +23703,12 @@ function __vue2_injectStyles$9(context) {
|
|
|
23703
23703
|
const RemoveFormatControl = /* @__PURE__ */ function() {
|
|
23704
23704
|
return __component__$9.exports;
|
|
23705
23705
|
}();
|
|
23706
|
+
const RegExps = {
|
|
23707
|
+
URL: /^(https:\/\/www\.|https:\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,100}(:[0-9]{1,5})?(\/.*)?$/i,
|
|
23708
|
+
HTTPS_PROTOCOL: /^https?:\/\/.+$/i,
|
|
23709
|
+
MAILTO_PROTOCOL: /^mailto:.+$/,
|
|
23710
|
+
TEL_PROTOCOL: /^tel:.+$/
|
|
23711
|
+
};
|
|
23706
23712
|
var render$8 = function __render__37() {
|
|
23707
23713
|
var _vm = this;
|
|
23708
23714
|
var _h = _vm.$createElement;
|
|
@@ -23785,9 +23791,13 @@ function useLink() {
|
|
|
23785
23791
|
function getFormattedHref() {
|
|
23786
23792
|
if (currentDestination.value.id === LinkDestinations.URL) {
|
|
23787
23793
|
const url = destinationHrefs.value.url;
|
|
23788
|
-
const
|
|
23789
|
-
|
|
23790
|
-
|
|
23794
|
+
const isTelOrMail = RegExps.TEL_PROTOCOL.test(url) || RegExps.MAILTO_PROTOCOL.test(url);
|
|
23795
|
+
if (isTelOrMail)
|
|
23796
|
+
return url;
|
|
23797
|
+
if (url.startsWith("/"))
|
|
23798
|
+
return url;
|
|
23799
|
+
const hasProtocol2 = RegExps.HTTPS_PROTOCOL.test(url);
|
|
23800
|
+
return hasProtocol2 ? url : `https://${url}`;
|
|
23791
23801
|
}
|
|
23792
23802
|
return destinationHrefs.value[currentDestination.value.id];
|
|
23793
23803
|
}
|
|
@@ -24185,22 +24195,26 @@ const __vue2_script$4 = {
|
|
|
24185
24195
|
const modalRef = ref(null);
|
|
24186
24196
|
const editor = inject(InjectionTokens$1.EDITOR);
|
|
24187
24197
|
const link = useLink();
|
|
24188
|
-
const urlRegExp = /^(https:\/\/www\.|https:\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,100}(:[0-9]{1,5})?(\/.*)?$/i;
|
|
24189
24198
|
const isEmpty = () => {
|
|
24190
24199
|
return link.linkData.value.text ? false : "Can't be empty";
|
|
24191
24200
|
};
|
|
24192
|
-
const
|
|
24201
|
+
const isValidUrl = () => {
|
|
24193
24202
|
if (link.currentDestination.value.id !== LinkDestinations.URL)
|
|
24194
24203
|
return false;
|
|
24195
24204
|
const href = link.destinationHrefs.value.url;
|
|
24196
|
-
const
|
|
24197
|
-
|
|
24205
|
+
const isTelOrMail = RegExps.TEL_PROTOCOL.test(href) || RegExps.MAILTO_PROTOCOL.test(href);
|
|
24206
|
+
if (isTelOrMail)
|
|
24207
|
+
return false;
|
|
24208
|
+
if (href.startsWith("/"))
|
|
24209
|
+
return false;
|
|
24210
|
+
const isUrl = RegExps.URL.test(href);
|
|
24211
|
+
return isUrl ? false : "Please enter a valid URL";
|
|
24198
24212
|
};
|
|
24199
24213
|
const nameValidator = useValidator({
|
|
24200
24214
|
validations: [isEmpty]
|
|
24201
24215
|
});
|
|
24202
24216
|
const urlValidator = useValidator({
|
|
24203
|
-
validations: [
|
|
24217
|
+
validations: [isValidUrl]
|
|
24204
24218
|
});
|
|
24205
24219
|
const resetErrors = () => {
|
|
24206
24220
|
nameValidator.reset();
|
|
@@ -24257,7 +24271,7 @@ var __component__$4 = /* @__PURE__ */ normalizeComponent(
|
|
|
24257
24271
|
staticRenderFns$4,
|
|
24258
24272
|
false,
|
|
24259
24273
|
__vue2_injectStyles$4,
|
|
24260
|
-
"
|
|
24274
|
+
"eea2f92a",
|
|
24261
24275
|
null,
|
|
24262
24276
|
null
|
|
24263
24277
|
);
|
|
@@ -25022,9 +25036,13 @@ const FontStyle = Mark.create({
|
|
|
25022
25036
|
});
|
|
25023
25037
|
}),
|
|
25024
25038
|
isItalicAvailable: createCommand(({ commands: commands2 }) => {
|
|
25025
|
-
const
|
|
25026
|
-
const
|
|
25027
|
-
return computed(() =>
|
|
25039
|
+
const fontRef = commands2.getFont();
|
|
25040
|
+
const fontWeightRef = commands2.getFontWeight();
|
|
25041
|
+
return computed(() => {
|
|
25042
|
+
const font = unref(fontRef);
|
|
25043
|
+
const weight = unref(fontWeightRef);
|
|
25044
|
+
return font.isItalicSupported(weight) && !font.isWeightItalicOnly(weight);
|
|
25045
|
+
});
|
|
25028
25046
|
}),
|
|
25029
25047
|
getDefaultFontStyle: createCommand(({ commands: commands2 }) => {
|
|
25030
25048
|
const preset = commands2.getPreset();
|
|
@@ -27808,19 +27826,21 @@ function buildExtensions(options) {
|
|
|
27808
27826
|
}
|
|
27809
27827
|
class Font {
|
|
27810
27828
|
constructor({ name, category, styles }) {
|
|
27829
|
+
__privateAdd(this, _getWeights);
|
|
27811
27830
|
this.name = name;
|
|
27812
27831
|
this.category = category;
|
|
27813
27832
|
this.styles = styles;
|
|
27814
|
-
|
|
27815
|
-
get weights() {
|
|
27816
|
-
return this.styles.filter((style2) => !style2.endsWith("i"));
|
|
27833
|
+
this.weights = __privateMethod(this, _getWeights, getWeights_fn).call(this);
|
|
27817
27834
|
}
|
|
27818
27835
|
isWeightSupported(weight) {
|
|
27819
|
-
return this.
|
|
27836
|
+
return this.weights.includes(weight);
|
|
27820
27837
|
}
|
|
27821
27838
|
isItalicSupported(weight) {
|
|
27822
27839
|
return this.styles.includes(`${weight}i`);
|
|
27823
27840
|
}
|
|
27841
|
+
isWeightItalicOnly(weight) {
|
|
27842
|
+
return this.isItalicSupported(weight) && !this.styles.includes(weight);
|
|
27843
|
+
}
|
|
27824
27844
|
findClosestWeight(searchedWeight) {
|
|
27825
27845
|
const weights = this.weights.map((weight) => parseInt(weight));
|
|
27826
27846
|
let closestWeight;
|
|
@@ -27835,6 +27855,11 @@ class Font {
|
|
|
27835
27855
|
return String(closestWeight);
|
|
27836
27856
|
}
|
|
27837
27857
|
}
|
|
27858
|
+
_getWeights = new WeakSet();
|
|
27859
|
+
getWeights_fn = function() {
|
|
27860
|
+
const weights = this.styles.map((style2) => style2.replace("i", ""));
|
|
27861
|
+
return Array.from(new Set(weights));
|
|
27862
|
+
};
|
|
27838
27863
|
var render = function __render__45() {
|
|
27839
27864
|
var _vm = this;
|
|
27840
27865
|
var _h = _vm.$createElement;
|
package/example/fonts.js
CHANGED
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
import { computed, ref, inject, unref } from 'vue';
|
|
43
43
|
import { LinkDestinations, TextSettings } from '../../../../enums';
|
|
44
44
|
import { InjectionTokens } from '../../../../injectionTokens';
|
|
45
|
+
import { RegExps } from '../../../../regExps';
|
|
45
46
|
import { tooltip } from '../../../../directives';
|
|
46
47
|
import { useValidator } from '../../../base/composables';
|
|
47
48
|
import { Button, Icon, Modal, TextField, useModalToggler } from '../../../base';
|
|
@@ -72,18 +73,23 @@ export default {
|
|
|
72
73
|
const editor = inject(InjectionTokens.EDITOR);
|
|
73
74
|
|
|
74
75
|
const link = useLink();
|
|
75
|
-
const urlRegExp = /^(https:\/\/www\.|https:\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,100}(:[0-9]{1,5})?(\/.*)?$/i;
|
|
76
76
|
|
|
77
77
|
const isEmpty = () => {
|
|
78
78
|
return link.linkData.value.text ? false : 'Can\'t be empty';
|
|
79
79
|
};
|
|
80
|
-
|
|
80
|
+
|
|
81
|
+
const isValidUrl = () => {
|
|
81
82
|
if (link.currentDestination.value.id !== LinkDestinations.URL) return false;
|
|
82
83
|
|
|
83
84
|
const href = link.destinationHrefs.value.url;
|
|
84
|
-
const
|
|
85
|
+
const isTelOrMail = RegExps.TEL_PROTOCOL.test(href) || RegExps.MAILTO_PROTOCOL.test(href);
|
|
86
|
+
|
|
87
|
+
if (isTelOrMail) return false;
|
|
88
|
+
if (href.startsWith('/')) return false;
|
|
89
|
+
|
|
90
|
+
const isUrl = RegExps.URL.test(href);
|
|
85
91
|
|
|
86
|
-
return
|
|
92
|
+
return isUrl ? false : 'Please enter a valid URL';
|
|
87
93
|
};
|
|
88
94
|
|
|
89
95
|
const nameValidator = useValidator({
|
|
@@ -91,7 +97,7 @@ export default {
|
|
|
91
97
|
});
|
|
92
98
|
|
|
93
99
|
const urlValidator = useValidator({
|
|
94
|
-
validations: [
|
|
100
|
+
validations: [isValidUrl]
|
|
95
101
|
});
|
|
96
102
|
|
|
97
103
|
const resetErrors = () => {
|
|
@@ -169,4 +169,36 @@ describe('format link', () => {
|
|
|
169
169
|
text: 'hello'
|
|
170
170
|
});
|
|
171
171
|
});
|
|
172
|
+
|
|
173
|
+
test('should format telephone link', () => {
|
|
174
|
+
const link = useComposable();
|
|
175
|
+
|
|
176
|
+
link.updateText('hello');
|
|
177
|
+
link.updateLink('tel:0123456789');
|
|
178
|
+
|
|
179
|
+
link.apply();
|
|
180
|
+
|
|
181
|
+
expect(link.editor.commands.applyLink).toHaveBeenCalledWith({
|
|
182
|
+
destination: LinkDestinations.URL,
|
|
183
|
+
href: 'tel:0123456789',
|
|
184
|
+
target: LinkTargets.SELF,
|
|
185
|
+
text: 'hello'
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('should format mail link', () => {
|
|
190
|
+
const link = useComposable();
|
|
191
|
+
|
|
192
|
+
link.updateText('hello');
|
|
193
|
+
link.updateLink('mailto:example@gmail.com');
|
|
194
|
+
|
|
195
|
+
link.apply();
|
|
196
|
+
|
|
197
|
+
expect(link.editor.commands.applyLink).toHaveBeenCalledWith({
|
|
198
|
+
destination: LinkDestinations.URL,
|
|
199
|
+
href: 'mailto:example@gmail.com',
|
|
200
|
+
target: LinkTargets.SELF,
|
|
201
|
+
text: 'hello'
|
|
202
|
+
});
|
|
203
|
+
});
|
|
172
204
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ref, inject } from 'vue';
|
|
2
2
|
import { LinkTargets, LinkDestinations, TextSettings } from '../../../../../enums';
|
|
3
3
|
import { InjectionTokens } from '../../../../../injectionTokens';
|
|
4
|
+
import { RegExps } from '../../../../../regExps';
|
|
4
5
|
|
|
5
6
|
export function useLink() {
|
|
6
7
|
const editor = inject(InjectionTokens.EDITOR);
|
|
@@ -34,10 +35,14 @@ export function useLink() {
|
|
|
34
35
|
function getFormattedHref() {
|
|
35
36
|
if (currentDestination.value.id === LinkDestinations.URL) {
|
|
36
37
|
const url = destinationHrefs.value.url;
|
|
37
|
-
const
|
|
38
|
-
const hasProtocol = /^https?:\/\/.+$/i.test(url);
|
|
38
|
+
const isTelOrMail = RegExps.TEL_PROTOCOL.test(url) || RegExps.MAILTO_PROTOCOL.test(url);
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
if (isTelOrMail) return url;
|
|
41
|
+
if (url.startsWith('/')) return url;
|
|
42
|
+
|
|
43
|
+
const hasProtocol = RegExps.HTTPS_PROTOCOL.test(url);
|
|
44
|
+
|
|
45
|
+
return hasProtocol ? url : `https://${url}`;
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
return destinationHrefs.value[currentDestination.value.id];
|
|
@@ -21,10 +21,15 @@ export const FontStyle = Mark.create({
|
|
|
21
21
|
}),
|
|
22
22
|
|
|
23
23
|
isItalicAvailable: createCommand(({ commands }) => {
|
|
24
|
-
const
|
|
25
|
-
const
|
|
24
|
+
const fontRef = commands.getFont();
|
|
25
|
+
const fontWeightRef = commands.getFontWeight();
|
|
26
26
|
|
|
27
|
-
return computed(() =>
|
|
27
|
+
return computed(() => {
|
|
28
|
+
const font = unref(fontRef);
|
|
29
|
+
const weight = unref(fontWeightRef);
|
|
30
|
+
|
|
31
|
+
return font.isItalicSupported(weight) && !font.isWeightItalicOnly(weight);
|
|
32
|
+
});
|
|
28
33
|
}),
|
|
29
34
|
|
|
30
35
|
getDefaultFontStyle: createCommand(({ commands }) => {
|
|
@@ -88,7 +88,9 @@ describe('get font family', () => {
|
|
|
88
88
|
content: createContent(NodeFactory.text('hello world'))
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
-
expect(editor.commands.findFontByName('Bungee')).toEqual(
|
|
91
|
+
expect(editor.commands.findFontByName('Bungee')).toEqual(
|
|
92
|
+
expect.objectContaining({ name: 'Bungee' })
|
|
93
|
+
);
|
|
92
94
|
});
|
|
93
95
|
|
|
94
96
|
test('should get font model from selection', () => {
|
package/lib/models/Font.js
CHANGED
|
@@ -3,20 +3,27 @@ export class Font {
|
|
|
3
3
|
this.name = name;
|
|
4
4
|
this.category = category;
|
|
5
5
|
this.styles = styles;
|
|
6
|
+
this.weights = this.#getWeights();
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
#getWeights() {
|
|
10
|
+
const weights = this.styles.map((style) => style.replace('i', ''));
|
|
11
|
+
|
|
12
|
+
return Array.from(new Set(weights));
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
isWeightSupported(weight) {
|
|
13
|
-
return this.
|
|
16
|
+
return this.weights.includes(weight);
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
isItalicSupported(weight) {
|
|
17
20
|
return this.styles.includes(`${weight}i`);
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
isWeightItalicOnly(weight) {
|
|
24
|
+
return this.isItalicSupported(weight) && !this.styles.includes(weight);
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
findClosestWeight(searchedWeight) {
|
|
21
28
|
const weights = this.weights.map((weight) => parseInt(weight));
|
|
22
29
|
|
|
@@ -9,6 +9,12 @@ describe('weights', () => {
|
|
|
9
9
|
expect(font.weights).toEqual(['400', '700']);
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
+
test('should display italic only style', () => {
|
|
13
|
+
const font = new Font({ styles: ['700i'] });
|
|
14
|
+
|
|
15
|
+
expect(font.weights).toEqual(['700']);
|
|
16
|
+
});
|
|
17
|
+
|
|
12
18
|
test('should find closest font weight', () => {
|
|
13
19
|
const font = new Font({ styles: ['400', '700'] });
|
|
14
20
|
const weight = font.findClosestWeight('500');
|
|
@@ -41,7 +47,7 @@ describe('style checks', () => {
|
|
|
41
47
|
test('should detect if weight not supported', () => {
|
|
42
48
|
const font = new Font({ styles: ['400', '700i'] });
|
|
43
49
|
|
|
44
|
-
expect(font.isWeightSupported('
|
|
50
|
+
expect(font.isWeightSupported('800')).toBe(false);
|
|
45
51
|
});
|
|
46
52
|
|
|
47
53
|
test('should detect if italic supported', () => {
|
|
@@ -55,4 +61,16 @@ describe('style checks', () => {
|
|
|
55
61
|
|
|
56
62
|
expect(font.isItalicSupported('700')).toBe(false);
|
|
57
63
|
});
|
|
64
|
+
|
|
65
|
+
test('should detect italic only weight', () => {
|
|
66
|
+
const font = new Font({ styles: ['400i'] });
|
|
67
|
+
|
|
68
|
+
expect(font.isItalicSupported('400')).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('should detect non italic only weight', () => {
|
|
72
|
+
const font = new Font({ styles: ['400i', '400'] });
|
|
73
|
+
|
|
74
|
+
expect(font.isItalicSupported('400')).toBe(true);
|
|
75
|
+
});
|
|
58
76
|
});
|
package/lib/regExps.js
ADDED