@vanduo-oss/framework 1.4.2 → 1.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/README.md +3 -3
- package/css/vanduo.css +0 -1
- package/dist/build-info.json +3 -3
- package/dist/vanduo.cjs.js +86 -1085
- package/dist/vanduo.cjs.js.map +3 -3
- package/dist/vanduo.cjs.min.js +8 -8
- package/dist/vanduo.cjs.min.js.map +4 -4
- package/dist/vanduo.css +1 -690
- package/dist/vanduo.css.map +1 -1
- package/dist/vanduo.esm.js +86 -1085
- package/dist/vanduo.esm.js.map +3 -3
- package/dist/vanduo.esm.min.js +8 -8
- package/dist/vanduo.esm.min.js.map +4 -4
- package/dist/vanduo.js +86 -1085
- package/dist/vanduo.js.map +3 -3
- package/dist/vanduo.min.css +2 -2
- package/dist/vanduo.min.css.map +1 -1
- package/dist/vanduo.min.js +8 -8
- package/dist/vanduo.min.js.map +4 -4
- package/js/components/code-snippet.js +73 -16
- package/js/components/datepicker.js +27 -1
- package/js/components/suggest.js +18 -15
- package/js/index.js +0 -1
- package/package.json +1 -1
- package/css/components/music-player.css +0 -798
- package/js/components/music-player.js +0 -1294
|
@@ -566,19 +566,65 @@
|
|
|
566
566
|
* @returns {string} HTML with syntax highlighting spans
|
|
567
567
|
*/
|
|
568
568
|
highlightHtml: function (html) {
|
|
569
|
-
//
|
|
570
|
-
html = html.replace(/(<
|
|
569
|
+
// Comments first so tag highlighting does not treat them as elements.
|
|
570
|
+
html = html.replace(/(<!--)(.*?)(-->)/g, '<span class="code-comment">$1$2$3</span>');
|
|
571
571
|
|
|
572
|
-
//
|
|
573
|
-
|
|
574
|
-
html = html.replace(
|
|
572
|
+
// Only highlight inside escaped HTML tags. Build the highlighted tag from the
|
|
573
|
+
// original escaped source so regexes never re-process our injected spans.
|
|
574
|
+
html = html.replace(/<(?!--)([\s\S]*?)>/g, function (match, inner) {
|
|
575
|
+
const closingMatch = inner.match(/^(\/)([\w-]+)\s*$/);
|
|
576
|
+
if (closingMatch) {
|
|
577
|
+
return '<'
|
|
578
|
+
+ closingMatch[1]
|
|
579
|
+
+ '<span class="code-tag">' + closingMatch[2] + '</span>'
|
|
580
|
+
+ '>';
|
|
581
|
+
}
|
|
575
582
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
583
|
+
const selfClosingMatch = inner.match(/(\s*\/)\s*$/);
|
|
584
|
+
const selfClosingSuffix = selfClosingMatch ? selfClosingMatch[1] : '';
|
|
585
|
+
const tagSource = selfClosingMatch
|
|
586
|
+
? inner.slice(0, inner.length - selfClosingMatch[0].length)
|
|
587
|
+
: inner;
|
|
588
|
+
const openMatch = tagSource.match(/^([\w-]+)([\s\S]*)$/);
|
|
579
589
|
|
|
580
|
-
|
|
581
|
-
|
|
590
|
+
if (!openMatch) {
|
|
591
|
+
return match;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const tagName = openMatch[1];
|
|
595
|
+
let attrSource = openMatch[2];
|
|
596
|
+
|
|
597
|
+
attrSource = attrSource.replace(
|
|
598
|
+
/([\w:-]+)(\s*=\s*)(["'])([\s\S]*?)\3/g,
|
|
599
|
+
function (attrMatch, attrName, separator, quote, value) {
|
|
600
|
+
return '<span class="code-attr">' + attrName + '</span>'
|
|
601
|
+
+ separator
|
|
602
|
+
+ quote
|
|
603
|
+
+ '<span class="code-string">' + value + '</span>'
|
|
604
|
+
+ quote;
|
|
605
|
+
}
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
attrSource = attrSource.replace(
|
|
609
|
+
/([\w:-]+)(\s*=\s*)("|')([\s\S]*?)("|')/g,
|
|
610
|
+
function (attrMatch, attrName, separator, openQuote, value, closeQuote) {
|
|
611
|
+
if (openQuote !== closeQuote) {
|
|
612
|
+
return attrMatch;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
return '<span class="code-attr">' + attrName + '</span>'
|
|
616
|
+
+ separator
|
|
617
|
+
+ openQuote
|
|
618
|
+
+ '<span class="code-string">' + value + '</span>'
|
|
619
|
+
+ closeQuote;
|
|
620
|
+
}
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
return '<<span class="code-tag">' + tagName + '</span>'
|
|
624
|
+
+ attrSource
|
|
625
|
+
+ selfClosingSuffix
|
|
626
|
+
+ '>';
|
|
627
|
+
});
|
|
582
628
|
|
|
583
629
|
return html;
|
|
584
630
|
},
|
|
@@ -613,6 +659,20 @@
|
|
|
613
659
|
* @returns {string} JS with syntax highlighting spans
|
|
614
660
|
*/
|
|
615
661
|
highlightJs: function (js) {
|
|
662
|
+
const protectedTokens = [];
|
|
663
|
+
const protectToken = (value, className) => {
|
|
664
|
+
const marker = String.fromCharCode(0xE000 + protectedTokens.length);
|
|
665
|
+
protectedTokens.push({ marker, html: '<span class="' + className + '">' + value + '</span>' });
|
|
666
|
+
return marker;
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
// Protect comments and strings before adding markup so later passes never
|
|
670
|
+
// re-highlight attributes inside the generated spans.
|
|
671
|
+
js = js.replace(
|
|
672
|
+
/\/\*[\s\S]*?\*\/|\/\/.*$|'(?:[^'\\]|\\.){0,10000}'|"(?:[^"\\]|\\.){0,10000}"|`(?:[^`\\]|\\.){0,10000}`/gm,
|
|
673
|
+
match => protectToken(match, match.startsWith('/') ? 'code-comment' : 'code-string')
|
|
674
|
+
);
|
|
675
|
+
|
|
616
676
|
// Highlight keywords
|
|
617
677
|
const keywords = ['const', 'let', 'var', 'function', 'return', 'if', 'else', 'for', 'while', 'switch', 'case', 'break', 'continue', 'new', 'this', 'class', 'extends', 'import', 'export', 'default', 'async', 'await', 'try', 'catch', 'throw', 'typeof', 'instanceof'];
|
|
618
678
|
keywords.forEach(kw => {
|
|
@@ -620,18 +680,15 @@
|
|
|
620
680
|
js = js.replace(regex, '<span class="code-keyword">$1</span>');
|
|
621
681
|
});
|
|
622
682
|
|
|
623
|
-
// Highlight strings (limit to 10 000 chars to prevent polynomial backtracking)
|
|
624
|
-
js = js.replace(/('(?:[^'\\]|\\.){0,10000}'|"(?:[^"\\]|\\.){0,10000}"|`(?:[^`\\]|\\.){0,10000}`)/g, '<span class="code-string">$1</span>');
|
|
625
|
-
|
|
626
683
|
// Highlight numbers
|
|
627
684
|
js = js.replace(/\b(\d+\.?\d*)\b/g, '<span class="code-number">$1</span>');
|
|
628
685
|
|
|
629
686
|
// Highlight function calls
|
|
630
687
|
js = js.replace(/\b([\w]+)(\s*\()/g, '<span class="code-function">$1</span>$2');
|
|
631
688
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
689
|
+
protectedTokens.forEach(token => {
|
|
690
|
+
js = js.replace(token.marker, token.html);
|
|
691
|
+
});
|
|
635
692
|
|
|
636
693
|
return js;
|
|
637
694
|
},
|
|
@@ -181,6 +181,8 @@
|
|
|
181
181
|
let focusedDate = null;
|
|
182
182
|
/** Prevents focus() after close from immediately re-opening the popup */
|
|
183
183
|
let skipNextFocusOpen = false;
|
|
184
|
+
/** Ignore outside-click closes briefly after open (mobile click/focus ordering). */
|
|
185
|
+
let ignoreOutsideUntil = 0;
|
|
184
186
|
|
|
185
187
|
const isDisabled = (d) => {
|
|
186
188
|
if (minDate) {
|
|
@@ -562,7 +564,12 @@
|
|
|
562
564
|
positionPopup();
|
|
563
565
|
};
|
|
564
566
|
|
|
567
|
+
const markIgnoreOutside = () => {
|
|
568
|
+
ignoreOutsideUntil = Date.now() + 100;
|
|
569
|
+
};
|
|
570
|
+
|
|
565
571
|
const open = () => {
|
|
572
|
+
markIgnoreOutside();
|
|
566
573
|
viewMode = 'days';
|
|
567
574
|
if (selectedDate) {
|
|
568
575
|
viewYear = selectedDate.getFullYear();
|
|
@@ -600,8 +607,25 @@
|
|
|
600
607
|
}
|
|
601
608
|
open();
|
|
602
609
|
};
|
|
610
|
+
/** Mobile browsers may not focus the input before the click event (Playwright too). */
|
|
611
|
+
const clickHandler = () => {
|
|
612
|
+
if (!popup.classList.contains('is-open')) open();
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
const isOpenAnchorTarget = (target) => {
|
|
616
|
+
if (!target || !(target instanceof Node)) return false;
|
|
617
|
+
if (target === input || input.contains(target) || popup.contains(target)) return true;
|
|
618
|
+
const inputId = input.id;
|
|
619
|
+
if (inputId) {
|
|
620
|
+
const label = document.querySelector('label[for="' + inputId.replace(/"/g, '\\"') + '"]');
|
|
621
|
+
if (label && (target === label || label.contains(target))) return true;
|
|
622
|
+
}
|
|
623
|
+
return false;
|
|
624
|
+
};
|
|
625
|
+
|
|
603
626
|
const outsideHandler = (e) => {
|
|
604
|
-
if (
|
|
627
|
+
if (Date.now() < ignoreOutsideUntil) return;
|
|
628
|
+
if (!isOpenAnchorTarget(e.target)) close();
|
|
605
629
|
};
|
|
606
630
|
const escHandler = (e) => {
|
|
607
631
|
if (e.key === 'Escape' && popup.classList.contains('is-open')) {
|
|
@@ -612,6 +636,7 @@
|
|
|
612
636
|
};
|
|
613
637
|
|
|
614
638
|
input.addEventListener('focus', focusHandler);
|
|
639
|
+
input.addEventListener('click', clickHandler);
|
|
615
640
|
document.addEventListener('click', outsideHandler, true);
|
|
616
641
|
document.addEventListener('keydown', escHandler);
|
|
617
642
|
popup.addEventListener('keydown', handleGridKeydown);
|
|
@@ -624,6 +649,7 @@
|
|
|
624
649
|
|
|
625
650
|
cleanup.push(
|
|
626
651
|
() => input.removeEventListener('focus', focusHandler),
|
|
652
|
+
() => input.removeEventListener('click', clickHandler),
|
|
627
653
|
() => document.removeEventListener('click', outsideHandler, true),
|
|
628
654
|
() => document.removeEventListener('keydown', escHandler),
|
|
629
655
|
() => popup.removeEventListener('keydown', handleGridKeydown),
|
package/js/components/suggest.js
CHANGED
|
@@ -6,17 +6,6 @@
|
|
|
6
6
|
(function () {
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Escape HTML entities to prevent XSS when inserting into innerHTML
|
|
11
|
-
* @param {string} text
|
|
12
|
-
* @returns {string}
|
|
13
|
-
*/
|
|
14
|
-
function _escapeHtml(text) {
|
|
15
|
-
const div = document.createElement('div');
|
|
16
|
-
div.textContent = text;
|
|
17
|
-
return div.innerHTML;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
9
|
/**
|
|
21
10
|
* Allow same-origin URLs by default, or an explicit allowlist of origins.
|
|
22
11
|
* @param {string} url
|
|
@@ -109,10 +98,24 @@
|
|
|
109
98
|
|
|
110
99
|
const text = typeof item === 'object' ? (item.label || item.text || String(item)) : String(item);
|
|
111
100
|
if (query) {
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
101
|
+
const lowerText = text.toLowerCase();
|
|
102
|
+
const lowerQuery = query.toLowerCase();
|
|
103
|
+
let start = 0;
|
|
104
|
+
let matchIndex = lowerText.indexOf(lowerQuery, start);
|
|
105
|
+
while (matchIndex !== -1) {
|
|
106
|
+
if (matchIndex > start) {
|
|
107
|
+
li.appendChild(document.createTextNode(text.slice(start, matchIndex)));
|
|
108
|
+
}
|
|
109
|
+
const matchSpan = document.createElement('span');
|
|
110
|
+
matchSpan.className = 'vd-suggest-match';
|
|
111
|
+
matchSpan.textContent = text.slice(matchIndex, matchIndex + query.length);
|
|
112
|
+
li.appendChild(matchSpan);
|
|
113
|
+
start = matchIndex + query.length;
|
|
114
|
+
matchIndex = lowerText.indexOf(lowerQuery, start);
|
|
115
|
+
}
|
|
116
|
+
if (start < text.length) {
|
|
117
|
+
li.appendChild(document.createTextNode(text.slice(start)));
|
|
118
|
+
}
|
|
116
119
|
} else {
|
|
117
120
|
li.textContent = text;
|
|
118
121
|
}
|
package/js/index.js
CHANGED