pxx-vue-quill 1.0.97 → 1.0.98

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.
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Copyright (c) 2025 Pxx-Team
9
9
  * Released under the MIT license
10
- * Date: 2025-09-09T02:34:04.777Z
10
+ * Date: 2025-09-09T11:01:46.299Z
11
11
  */
12
12
  (function (global, factory) {
13
13
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue')) :
@@ -18444,7 +18444,7 @@
18444
18444
  full: [
18445
18445
  ['bold', 'italic', 'underline'],
18446
18446
  [{ color: [] }],
18447
- ['link'],
18447
+ ['customLink'],
18448
18448
  [{ list: 'ordered' }, { list: 'bullet' }],
18449
18449
  ['image'],
18450
18450
  ['undo', 'redo'],
@@ -18517,8 +18517,9 @@
18517
18517
  ]),
18518
18518
  vue.h('span', { class: 'ql-formats' }, [
18519
18519
  vue.h('button', {
18520
- class: 'ql-link',
18521
- type: 'button'
18520
+ class: 'ql-customLink',
18521
+ type: 'button',
18522
+ onClick: () => emit('toolClick', 'customLink')
18522
18523
  }, '')
18523
18524
  ]),
18524
18525
  vue.h('span', { class: 'ql-formats' }, [
@@ -18590,6 +18591,80 @@
18590
18591
  }
18591
18592
  });
18592
18593
 
18594
+ const CustomLink = vue.defineComponent({
18595
+ name: 'CustomLink',
18596
+ props: {
18597
+ visible: {
18598
+ type: Boolean,
18599
+ default: false
18600
+ },
18601
+ position: {
18602
+ type: Object,
18603
+ default: () => ({ top: 0, left: 0 })
18604
+ },
18605
+ linkUrl: {
18606
+ type: String,
18607
+ default: ''
18608
+ },
18609
+ linkText: {
18610
+ type: String,
18611
+ default: ''
18612
+ }
18613
+ },
18614
+ emits: ['save', 'update:linkUrl', 'update:linkText'],
18615
+ setup(props, { emit }) {
18616
+ const localLinkUrl = vue.computed({
18617
+ get() {
18618
+ return props.linkUrl;
18619
+ },
18620
+ set(val) {
18621
+ emit('update:linkUrl', val);
18622
+ },
18623
+ });
18624
+ const localLinkText = vue.computed({
18625
+ get() {
18626
+ return props.linkText;
18627
+ },
18628
+ set(val) {
18629
+ emit('update:linkText', val);
18630
+ },
18631
+ });
18632
+ const handleSave = () => {
18633
+ emit('save', {
18634
+ url: localLinkUrl.value,
18635
+ text: localLinkText.value
18636
+ });
18637
+ };
18638
+ return () => {
18639
+ if (!props.visible)
18640
+ return null;
18641
+ return vue.h('div', {
18642
+ class: 'ql-custom-link',
18643
+ style: {
18644
+ top: `${props.position.top}px`,
18645
+ left: `${props.position.left}px`,
18646
+ },
18647
+ onClick: (event) => {
18648
+ event.stopPropagation();
18649
+ }
18650
+ }, [
18651
+ vue.h('input', {
18652
+ type: 'text',
18653
+ value: localLinkUrl.value,
18654
+ placeholder: '请输入链接',
18655
+ onInput: (e) => {
18656
+ localLinkUrl.value = e.target.value;
18657
+ }
18658
+ }),
18659
+ vue.h('button', {
18660
+ class: 'custom-link-btn',
18661
+ onClick: handleSave
18662
+ }, '确定'),
18663
+ ]);
18664
+ };
18665
+ }
18666
+ });
18667
+
18593
18668
  var dist = {};
18594
18669
 
18595
18670
  var Options = {};
@@ -20241,6 +20316,64 @@
20241
20316
  };
20242
20317
  }
20243
20318
 
20319
+ function useLinkClick(editor, initialHandleCustomLink) {
20320
+ const quillRef = vue.ref(null);
20321
+ const handleCustomLinkRef = vue.ref(initialHandleCustomLink || null);
20322
+ const handleLinkClick = (event) => {
20323
+ if (!quillRef.value || !handleCustomLinkRef.value)
20324
+ return;
20325
+ const target = event.target;
20326
+ if (target.tagName === 'A') {
20327
+ event.preventDefault();
20328
+ event.stopPropagation();
20329
+ try {
20330
+ const linkElement = target;
20331
+ const linkUrl = linkElement.getAttribute('href') || '';
20332
+ const linkText = linkElement.textContent || '';
20333
+ const range = quillRef.value.getSelection();
20334
+ if (range) {
20335
+ const [blot] = quillRef.value.getLeaf(range.index);
20336
+ if (blot && blot.parent && blot.parent.domNode.tagName === 'A') {
20337
+ const linkBlot = blot.parent;
20338
+ const linkIndex = quillRef.value.getIndex(linkBlot);
20339
+ const linkLength = linkBlot.length();
20340
+ quillRef.value.setSelection(linkIndex, linkLength);
20341
+ handleCustomLinkRef.value(true, { url: linkUrl, text: linkText });
20342
+ }
20343
+ }
20344
+ }
20345
+ catch (error) {
20346
+ console.warn('选中链接失败:', error);
20347
+ }
20348
+ }
20349
+ };
20350
+ const addLinkClickListener = () => {
20351
+ if (!quillRef.value)
20352
+ return;
20353
+ vue.nextTick(() => {
20354
+ var _a;
20355
+ const editorElement = (_a = editor.value) === null || _a === void 0 ? void 0 : _a.querySelector('.ql-editor');
20356
+ if (editorElement) {
20357
+ editorElement.removeEventListener('click', handleLinkClick);
20358
+ editorElement.addEventListener('click', handleLinkClick);
20359
+ }
20360
+ });
20361
+ };
20362
+ const setQuill = (quillInstance) => {
20363
+ quillRef.value = quillInstance;
20364
+ };
20365
+ const setHandleCustomLink = (fn) => {
20366
+ handleCustomLinkRef.value = fn;
20367
+ };
20368
+ return {
20369
+ quillRef,
20370
+ setQuill,
20371
+ setHandleCustomLink,
20372
+ handleLinkClick,
20373
+ addLinkClickListener
20374
+ };
20375
+ }
20376
+
20244
20377
  const boldSVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="18" height="18" viewBox="0 0 18 18"><g><g style="opacity:0;"><rect x="0" y="0" width="18" height="18" rx="0" fill="#FFFFFF" fill-opacity="1"/></g><g><path d="M6.794999938146972,7.7800002288818355L9.045000038146974,7.7800002288818355Q9.855000038146972,7.7800002288818355,10.230000038146972,7.442500128881836Q10.605000038146972,7.105000028881836,10.605000038146972,6.505000128881836Q10.605000038146972,6.114999728881836,10.440000038146973,5.860000628881836Q10.275000138146972,5.6050005288818365,9.929999838146973,5.470000228881836Q9.585000038146973,5.335000028881836,9.045000038146974,5.335000028881836L7.139999938146973,5.335000028881836L7.139999938146973,3.385000228881836L9.045000038146974,3.385000228881836Q10.034999838146973,3.385000228881836,10.852499938146973,3.797500608881836Q11.670000038146974,4.2100000388818355,12.142499938146972,4.922500628881836Q12.614999738146974,5.635000228881836,12.614999738146974,6.505000128881836Q12.614999738146974,7.375000028881836,12.142499938146972,8.042500028881836Q11.670000038146974,8.710000028881836,10.860000138146972,9.070000128881837Q10.050000238146973,9.430000328881835,9.045000038146974,9.430000328881835L6.794999938146972,9.430000328881835L6.794999938146972,7.7800002288818355ZM7.139999938146973,12.550000228881835L9.329999938146972,12.550000228881835Q9.900000138146972,12.550000228881835,10.327499838146974,12.354999528881836Q10.755000138146972,12.159999828881835,10.987500238146973,11.807499928881835Q11.219999838146972,11.454999928881836,11.219999838146972,11.020000428881836Q11.219999838146972,10.600000428881836,10.987500238146973,10.232500028881836Q10.755000138146972,9.864999728881836,10.327499838146974,9.647500028881836Q9.900000138146972,9.430000328881835,9.329999938146972,9.430000328881835L6.975000038146972,9.430000328881835L6.975000038146972,7.7800002288818355L9.329999938146972,7.7800002288818355Q10.349999938146972,7.7800002288818355,11.250000038146972,8.200000328881835Q12.149999638146973,8.620000328881837,12.690000538146972,9.362500228881835Q13.229999538146973,10.104999528881836,13.229999538146973,11.034999828881837Q13.229999538146973,11.949999828881836,12.690000538146972,12.752500528881836Q12.149999638146973,13.555000228881836,11.250000038146972,14.027500228881836Q10.349999938146972,14.500000228881836,9.329999938146972,14.500000228881836L7.139999938146973,14.500000228881836L7.139999938146973,12.550000228881835ZM7.064999938146973,14.500000228881836Q6.284999968146972,14.500000228881836,5.872500058146973,14.095000228881837Q5.460000038146973,13.689999228881836,5.460000038146973,12.895000428881836L5.460000038146973,4.989999728881836Q5.460000038146973,4.195000648881836,5.872500058146973,3.789999958881836Q6.284999968146972,3.385000228881836,7.064999938146973,3.385000228881836L7.469999838146973,3.385000228881836L7.469999838146973,14.500000228881836L7.064999938146973,14.500000228881836Z" fill="#555555" fill-opacity="1"/></g></g></svg>`;
20245
20378
  const italicSVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="18" height="18" viewBox="0 0 18 18"><g><g style="opacity:0;"><rect x="0" y="0" width="18" height="18" rx="0" fill="#FFFFFF" fill-opacity="1"/></g><g><path d="M8,3Q7.9015086,3,7.8049095,3.019214718Q7.7083106,3.038429435,7.6173165,3.076120459Q7.5263224,3.11381148,7.4444296,3.16853037Q7.3625371,3.2232492600000002,7.2928932,3.2928932Q7.2232492,3.36253715,7.1685302,3.4444297600000002Q7.1138113999999995,3.52632231,7.0761204,3.61731648Q7.0384293,3.70831072,7.0192146,3.80490965Q6.99999994,3.90150857,7,4Q6.99999994,4.0984913,7.0192146,4.1950902Q7.0384293,4.291689,7.0761204,4.3826833Q7.1138113999999995,4.4736774,7.1685302,4.5555699Q7.2232492,4.6374626,7.2928932,4.7071065999999995Q7.3625371,4.7767504,7.4444296,4.8314693Q7.5263224,4.8861883,7.6173165,4.9238794Q7.7083106,4.9615704,7.8049096,4.9807851Q7.9015086,4.9999999,8,5L9.137146,5L8,13L7,13Q6.90150857,13,6.80490965,13.019215Q6.70831072,13.038429,6.6173164799999995,13.07612Q6.52632231,13.113811,6.44442973,13.16853Q6.36253715,13.223249,6.2928932,13.292892Q6.22324926,13.362536,6.16853037,13.444429Q6.11381148,13.526321,6.076120459,13.617315Q6.038429435,13.708309,6.019214718,13.804909Q6,13.901508,6,14Q6,14.098491,6.019214718,14.195089Q6.038429435,14.291689,6.076120459,14.382683Q6.11381148,14.473677,6.16853037,14.555569Q6.22324926,14.637462,6.2928932,14.707106Q6.36253715,14.77675,6.44442976,14.831469Q6.52632231,14.886187,6.6173164799999995,14.923878Q6.70831072,14.961569,6.80490965,14.980784Q6.90150857,15,7,15L11,15Q11.0984912,15,11.1950898,14.980784Q11.2916889,14.961569,11.382682800000001,14.923878Q11.473677200000001,14.886187,11.5555696,14.831469Q11.6374626,14.77675,11.7071066,14.707106Q11.7767506,14.637462,11.8314691,14.555569Q11.8861876,14.473677,11.9238791,14.382683Q11.9615698,14.291689,11.9807849,14.195089Q12,14.098491,12,14Q12,13.901508,11.9807849,13.804909Q11.9615698,13.708309,11.9238791,13.617315Q11.8861876,13.526321,11.8314691,13.444428Q11.7767506,13.362536,11.7071066,13.292892Q11.6374626,13.223249,11.5555701,13.16853Q11.473677200000001,13.113811,11.382682800000001,13.07612Q11.2916889,13.038429,11.1950903,13.019215Q11.0984912,13,11,13L9.8626451,13L11,5L12,5Q12.0984907,4.9999999,12.1950893,4.9807851Q12.2916884,4.9615703,12.382682800000001,4.9238793Q12.4736767,4.8861883,12.5555696,4.8314693Q12.6374621,4.7767504,12.7071061,4.7071065999999995Q12.776750100000001,4.6374626,12.831468600000001,4.5555699Q12.8861876,4.4736774,12.9238787,4.3826833Q12.9615698,4.291689,12.9807849,4.1950902Q12.999999500000001,4.0984913,13,4Q12.999999500000001,3.90150857,12.980784400000001,3.80490965Q12.9615698,3.70831072,12.9238787,3.61731648Q12.8861876,3.52632231,12.8314691,3.44442973Q12.7767506,3.36253715,12.7071066,3.2928932Q12.6374626,3.2232492600000002,12.5555696,3.16853037Q12.4736767,3.11381148,12.382682800000001,3.076120459Q12.2916884,3.038429435,12.1950898,3.019214718Q12.0984907,3,12,3L8,3Z" fill-rule="evenodd" fill="#555555" fill-opacity="1"/></g></g></svg>`;
20246
20379
  const underlineSVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="18" height="18" viewBox="0 0 18 18"><g><g style="opacity:0;"><rect x="0" y="0" width="18" height="18" rx="0" fill="#FFFFFF" fill-opacity="1"/></g><g><path d="M5.000117301940918,14.500022450683593L5.000117301940918,14.500022450683593Q5.000117301940918,14.450777450683594,5.009724660740918,14.402477450683593Q5.019332019940918,14.354177450683594,5.038177530940918,14.308679450683593Q5.057023040940918,14.263182450683594,5.084382488940918,14.222236450683594Q5.111741931940918,14.181290450683594,5.146563901940918,14.146469450683593Q5.181385871940918,14.111646450683594,5.222332181940918,14.084286450683594Q5.263278451940918,14.056927450683594,5.308775541940918,14.038082450683595Q5.354272661940918,14.019237450683594,5.402572121940918,14.009630450683593Q5.450871581940918,14.000022450683593,5.500117301940918,14.000022450683593L12.500117301940918,14.000022450683593Q12.549362201940918,14.000022450683593,12.597661501940918,14.009629450683594Q12.645960801940918,14.019237450683594,12.691457701940918,14.038082450683595Q12.736954701940917,14.056926450683594,12.777901601940918,14.084285450683593Q12.818847701940918,14.111645450683593,12.853670101940917,14.146468450683594Q12.888492101940919,14.181289450683593,12.915851601940918,14.222235450683593Q12.943210601940919,14.263181450683593,12.962056201940918,14.308679450683593Q12.980901701940919,14.354177450683594,12.990509501940917,14.402477450683593Q13.00011680194092,14.450777450683594,13.000117301940918,14.500022450683593L13.000117301940918,14.500022450683593Q13.00011680194092,14.549268450683593,12.990509001940918,14.597566450683594Q12.980901701940919,14.645866450683593,12.962056201940918,14.691363450683594Q12.943210601940919,14.736860450683594,12.915851601940918,14.777807450683595Q12.888492101940919,14.818753450683595,12.853670101940917,14.853575450683593Q12.818847701940918,14.888397450683593,12.777901601940918,14.915756450683594Q12.736954701940917,14.943115450683594,12.691457701940918,14.961960450683593Q12.645960801940918,14.980806450683593,12.597661501940918,14.990413450683594Q12.549362201940918,15.000021450683594,12.500117301940918,15.000022450683593L5.500117301940918,15.000022450683593Q5.450871581940918,15.000021450683594,5.402572121940918,14.990414450683593Q5.354272661940918,14.980806450683593,5.308775541940918,14.961960450683593Q5.263278451940918,14.943115450683594,5.222332161940918,14.915756450683594Q5.181385871940918,14.888397450683593,5.146563901940918,14.853574450683594Q5.111741931940918,14.818752450683593,5.084382488940918,14.777806450683594Q5.057023040940918,14.736860450683594,5.038177530940918,14.691363450683594Q5.019332019940918,14.645866450683593,5.009724660740918,14.597567450683593Q5.000117301940918,14.549268450683593,5.000117301940918,14.500022450683593ZM5.045039176940918,3.548906330683594Q5.045039176940918,3.1015625006835936,5.283039211940918,2.8637809706835937Q5.521039131940918,2.6259994506835938,5.969039081940918,2.6259994506835938L5.997039201940918,2.6259994506835938Q6.445039201940918,2.6259994506835938,6.6830393019409176,2.8637809706835937Q6.921039201940918,3.1015625006835936,6.921039201940918,3.548906330683594L6.921039201940918,9.010000250683593Q6.921039201940918,9.737999950683594,7.180039401940919,10.255999550683594Q7.439039201940918,10.774000150683595,7.908039101940918,11.053999950683593Q8.377039001940918,11.333999650683594,8.993039101940917,11.333999650683594Q9.609039301940918,11.333999650683594,10.085039101940918,11.060999850683594Q10.561039401940917,10.788000150683594,10.820039301940918,10.263000450683593Q11.079039101940918,9.737999950683594,11.079039101940918,9.010000250683593L11.079039101940918,3.548906330683594Q11.079039101940918,3.1015625006835936,11.317039501940918,2.8637809706835937Q11.555039401940917,2.6259994506835938,12.003039401940917,2.6259994506835938L12.031039201940917,2.6259994506835938Q12.479039201940918,2.6259994506835938,12.717039101940918,2.8637809706835937Q12.955039001940918,3.1015625006835936,12.955039001940918,3.548906330683594L12.955039001940918,9.010000250683593Q12.955039001940918,10.144000050683594,12.416039501940919,11.095999750683594Q11.877039901940918,12.048000350683594,10.967039101940918,12.600999850683595Q10.057039301940918,13.154000450683593,8.993039101940917,13.154000450683593Q7.929039001940918,13.154000450683593,7.0190392019409185,12.600999850683595Q6.109039201940918,12.048000350683594,5.577039361940918,11.095999750683594Q5.045039176940918,10.144000050683594,5.045039176940918,9.010000250683593L5.045039176940918,3.548906330683594Z" fill="#555555" fill-opacity="1"/></g></g></svg>`;
@@ -20334,7 +20467,14 @@
20334
20467
  const showMoreToolbar = vue.ref(false);
20335
20468
  const canUndo = vue.ref(false);
20336
20469
  const canRedo = vue.ref(false);
20470
+ const showLinkDialog = vue.ref(false);
20471
+ const linkUrl = vue.ref('');
20472
+ const linkText = vue.ref('');
20473
+ const canUseLink = vue.ref(false);
20474
+ const linkPosition = vue.ref({ top: 0, left: 0 });
20475
+ const savedRange = vue.ref(null);
20337
20476
  const { setQuill, removeQuillBlotFormatter, configureBlotFormatter, applyImageStyle, registerBlotFormatter, getBlotFormatterConfig } = useBlotFormatter(editor, props.enableImageResize);
20477
+ const { setQuill: setLinkQuill, setHandleCustomLink, addLinkClickListener } = useLinkClick(editor);
20338
20478
  vue.onMounted(() => {
20339
20479
  initialize();
20340
20480
  });
@@ -20379,6 +20519,7 @@
20379
20519
  icons['underline'] = underlineSVG;
20380
20520
  icons['more'] = moreSVG;
20381
20521
  icons['link'] = linkSVG;
20522
+ icons['customLink'] = linkSVG;
20382
20523
  icons['undo'] = undoSVG;
20383
20524
  icons['redo'] = redoSVG;
20384
20525
  icons['ocr'] = ocrSVG;
@@ -20408,6 +20549,7 @@
20408
20549
  if (toolbar) {
20409
20550
  const undoBtn = toolbar.querySelector('.ql-undo');
20410
20551
  const redoBtn = toolbar.querySelector('.ql-redo');
20552
+ const customLinkBtn = toolbar.querySelector('.ql-customLink');
20411
20553
  if (undoBtn) {
20412
20554
  if (canUndo.value) {
20413
20555
  undoBtn.classList.remove('ql-disabled');
@@ -20426,10 +20568,19 @@
20426
20568
  }
20427
20569
  redoBtn.disabled = !canRedo.value;
20428
20570
  }
20571
+ if (customLinkBtn) {
20572
+ if (canUseLink.value) {
20573
+ customLinkBtn.classList.remove('ql-disabled');
20574
+ }
20575
+ else {
20576
+ customLinkBtn.classList.add('ql-disabled');
20577
+ }
20578
+ customLinkBtn.disabled = !canUseLink.value;
20579
+ }
20429
20580
  }
20430
20581
  };
20431
20582
  const initialize = () => {
20432
- var _a, _b;
20583
+ var _a;
20433
20584
  if (!editor.value)
20434
20585
  return;
20435
20586
  if (props.enableImageResize) {
@@ -20439,20 +20590,28 @@
20439
20590
  setIcons();
20440
20591
  quill = new Quill(editor.value, options);
20441
20592
  setQuill(quill);
20442
- const toolbar = (_a = quill === null || quill === void 0 ? void 0 : quill.getModule('toolbar')) === null || _a === void 0 ? void 0 : _a.container;
20443
- if (toolbar) {
20444
- toolbar.style.display = 'none';
20445
- }
20593
+ setLinkQuill(quill);
20594
+ controlToolbarVisible(false);
20446
20595
  setContents(props.content);
20447
20596
  quill.on('text-change', handleTextChange);
20448
20597
  quill.on('selection-change', handleSelectionChange);
20449
20598
  quill.on('editor-change', handleEditorChange);
20450
20599
  quill.on('text-change', updateHistoryState);
20451
20600
  quill.on('selection-change', updateHistoryState);
20601
+ addLinkClickListener();
20452
20602
  updateHistoryState();
20453
- const toolbarDom = (_b = quill.getModule('toolbar')) === null || _b === void 0 ? void 0 : _b.container;
20454
- toolbarDom.addEventListener('mousedown', (e) => {
20455
- e.preventDefault();
20603
+ const toolbarDom = (_a = quill.getModule('toolbar')) === null || _a === void 0 ? void 0 : _a.container;
20604
+ vue.nextTick(() => {
20605
+ const customLinkBtn = toolbarDom.querySelector('.ql-customLink');
20606
+ if (customLinkBtn) {
20607
+ customLinkBtn.addEventListener('click', (e) => {
20608
+ e.preventDefault();
20609
+ e.stopPropagation();
20610
+ if (canUseLink.value) {
20611
+ handleCustomLink(true);
20612
+ }
20613
+ });
20614
+ }
20456
20615
  });
20457
20616
  const tooltipInput = toolbarDom.querySelector('.ql-tooltip input');
20458
20617
  if (tooltipInput) {
@@ -20488,6 +20647,11 @@
20488
20647
  ...toolbarOptions.full,
20489
20648
  ],
20490
20649
  handlers: {
20650
+ customLink: function () {
20651
+ if (canUseLink.value) {
20652
+ handleCustomLink(true);
20653
+ }
20654
+ },
20491
20655
  redo: function () {
20492
20656
  var _a;
20493
20657
  if (canRedo.value) {
@@ -20565,22 +20729,25 @@
20565
20729
  preview.setAttribute('href', 'javascript:void(0)');
20566
20730
  preview.setAttribute('target', '_self');
20567
20731
  };
20732
+ const controlToolbarVisible = (visible) => {
20733
+ var _a;
20734
+ const toolbar = (_a = quill === null || quill === void 0 ? void 0 : quill.getModule('toolbar')) === null || _a === void 0 ? void 0 : _a.container;
20735
+ if (toolbar) {
20736
+ toolbar.style.display = visible ? 'block' : 'none';
20737
+ props.needCollapse && (showMoreToolbar.value = false);
20738
+ ctx.emit('toolbarVisibleChange', visible);
20739
+ }
20740
+ };
20568
20741
  const isEditorFocus = vue.ref();
20569
20742
  const handleSelectionChange = (range, oldRange, source) => {
20570
- var _a;
20571
20743
  observeTooltip();
20572
20744
  isEditorFocus.value = !!(quill === null || quill === void 0 ? void 0 : quill.hasFocus());
20573
- const toolbar = (_a = quill === null || quill === void 0 ? void 0 : quill.getModule('toolbar')) === null || _a === void 0 ? void 0 : _a.container;
20574
- if (toolbar) {
20575
- if (isEditorFocus.value) {
20576
- toolbar.style.display = 'block';
20577
- ctx.emit('toolbarVisibleChange', true);
20578
- }
20579
- else {
20580
- toolbar.style.display = 'none';
20581
- showMoreToolbar.value = false;
20582
- ctx.emit('toolbarVisibleChange', true);
20583
- }
20745
+ canUseLink.value = !!(range && range.length > 0);
20746
+ if (isEditorFocus.value) {
20747
+ controlToolbarVisible(true);
20748
+ }
20749
+ else {
20750
+ controlToolbarVisible(false);
20584
20751
  }
20585
20752
  ctx.emit('selectionChange', { range, oldRange, source });
20586
20753
  };
@@ -20710,6 +20877,79 @@
20710
20877
  else if (tool === 'more') {
20711
20878
  showMoreToolbar.value = !showMoreToolbar.value;
20712
20879
  }
20880
+ else if (tool === 'customLink') {
20881
+ handleCustomLink(true);
20882
+ }
20883
+ };
20884
+ const calculateSelectionPosition = (range) => {
20885
+ if (!quill)
20886
+ return { top: 0, left: 0 };
20887
+ const selectionRange = range || quill.getSelection();
20888
+ if (!selectionRange || selectionRange.length === 0)
20889
+ return { top: 0, left: 0 };
20890
+ try {
20891
+ const bounds = quill.getBounds(selectionRange.index, selectionRange.length);
20892
+ return {
20893
+ top: bounds.top + bounds.height + 5,
20894
+ left: bounds.left
20895
+ };
20896
+ }
20897
+ catch (error) {
20898
+ console.warn('计算选中位置时出错:', error);
20899
+ return { top: 0, left: 0 };
20900
+ }
20901
+ };
20902
+ const handleCustomLink = (bool, linkInfo) => {
20903
+ if (!quill)
20904
+ return;
20905
+ if (bool) {
20906
+ controlToolbarVisible(false);
20907
+ if (linkInfo) {
20908
+ linkUrl.value = linkInfo.url;
20909
+ linkText.value = linkInfo.text;
20910
+ const range = quill.getSelection();
20911
+ savedRange.value = range ? { ...range } : null;
20912
+ }
20913
+ else {
20914
+ const range = quill.getSelection();
20915
+ if (range && range.length > 0) {
20916
+ savedRange.value = { ...range };
20917
+ const selectedText = quill.getText(range.index, range.length);
20918
+ linkText.value = selectedText;
20919
+ }
20920
+ else {
20921
+ savedRange.value = range ? { ...range } : null;
20922
+ linkText.value = '';
20923
+ }
20924
+ }
20925
+ const range = quill.getSelection();
20926
+ linkPosition.value = calculateSelectionPosition(range || undefined);
20927
+ }
20928
+ else {
20929
+ savedRange.value = null;
20930
+ }
20931
+ showLinkDialog.value = bool;
20932
+ };
20933
+ setHandleCustomLink(handleCustomLink);
20934
+ const saveLink = (data) => {
20935
+ console.log("data", data);
20936
+ if (!quill || !data.url.trim())
20937
+ return;
20938
+ const range = savedRange.value;
20939
+ if (!range)
20940
+ return;
20941
+ if (range.length > 0) {
20942
+ quill.formatText(range.index, range.length, 'link', data.url);
20943
+ }
20944
+ else {
20945
+ const text = data.text || data.url;
20946
+ quill.insertText(range.index, text, { link: data.url });
20947
+ quill.setSelection(range.index + text.length, 0);
20948
+ }
20949
+ showLinkDialog.value = false;
20950
+ linkUrl.value = '';
20951
+ linkText.value = '';
20952
+ savedRange.value = null;
20713
20953
  };
20714
20954
  vue.watch(() => props.content, (newContent) => {
20715
20955
  if (!quill || internalModelEquals(newContent))
@@ -20730,6 +20970,11 @@
20730
20970
  showMoreToolbar,
20731
20971
  canUndo,
20732
20972
  canRedo,
20973
+ canUseLink,
20974
+ showLinkDialog,
20975
+ linkUrl,
20976
+ linkText,
20977
+ linkPosition,
20733
20978
  getEditor,
20734
20979
  getToolbar,
20735
20980
  getQuill,
@@ -20742,12 +20987,18 @@
20742
20987
  getText,
20743
20988
  setText,
20744
20989
  reinit,
20745
- moreToolbarToolClick
20990
+ moreToolbarToolClick,
20991
+ saveLink,
20992
+ handleCustomLink
20746
20993
  };
20747
20994
  },
20748
20995
  render() {
20749
20996
  return [
20750
- vue.h('div', { class: this.editorWrapClass }, [
20997
+ vue.h('div', {
20998
+ class: this.editorWrapClass, onClick: () => {
20999
+ this.handleCustomLink(false);
21000
+ }
21001
+ }, [
20751
21002
  this.$props.needCollapse && this.$props.editorKey && vue.h(MoreToolbar, {
20752
21003
  editorKey: String(this.$props.editorKey),
20753
21004
  needCollapse: this.needCollapse,
@@ -20760,8 +21011,19 @@
20760
21011
  }
20761
21012
  }),
20762
21013
  vue.h('div', {
20763
- ref: 'editor', ...this.$attrs
21014
+ ref: 'editor',
21015
+ style: { position: 'relative' },
21016
+ ...this.$attrs
20764
21017
  }),
21018
+ vue.h(CustomLink, {
21019
+ visible: this.showLinkDialog,
21020
+ position: this.linkPosition,
21021
+ linkUrl: this.linkUrl,
21022
+ linkText: this.linkText,
21023
+ 'onUpdate:linkUrl': (value) => { this.linkUrl = value; },
21024
+ 'onUpdate:linkText': (value) => { this.linkText = value; },
21025
+ onSave: this.saveLink,
21026
+ })
20765
21027
  ]),
20766
21028
  ];
20767
21029
  },