mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-16 22:50:13 +01:00
🎨 Improve code block language selection (#15966)
This commit is contained in:
parent
370eb68266
commit
a0593724a2
1 changed files with 72 additions and 49 deletions
|
|
@ -1236,10 +1236,19 @@ export class Toolbar {
|
||||||
hideElements(["hint"], protyle);
|
hideElements(["hint"], protyle);
|
||||||
window.siyuan.menus.menu.remove();
|
window.siyuan.menus.menu.remove();
|
||||||
this.range = getEditorRange(nodeElement);
|
this.range = getEditorRange(nodeElement);
|
||||||
let html = `<div class="b3-list-item">${window.siyuan.languages.clear}</div>`;
|
|
||||||
|
this.subElement.style.width = "";
|
||||||
|
this.subElement.style.padding = "";
|
||||||
|
this.subElement.innerHTML = `<div data-id="codeLanguage" class="fn__flex-column" style="max-height:50vh">
|
||||||
|
<input placeholder="${window.siyuan.languages.search}" style="margin: 0 8px 4px 8px" class="b3-text-field"/>
|
||||||
|
<div class="b3-list fn__flex-1 b3-list--background" style="position: relative"></div>
|
||||||
|
</div>`;
|
||||||
|
const listElement = this.subElement.lastElementChild.lastElementChild as HTMLElement;
|
||||||
|
|
||||||
|
let html = `<div data-id="clearLanguage" class="b3-list-item">${window.siyuan.languages.clear}</div>`;
|
||||||
let hljsLanguages = Constants.ALIAS_CODE_LANGUAGES.concat(window.hljs?.listLanguages() ?? []).sort();
|
let hljsLanguages = Constants.ALIAS_CODE_LANGUAGES.concat(window.hljs?.listLanguages() ?? []).sort();
|
||||||
|
|
||||||
const eventDetail = {languages: hljsLanguages};
|
const eventDetail = {languages: hljsLanguages, type: "init", listElement};
|
||||||
if (protyle.app && protyle.app.plugins) {
|
if (protyle.app && protyle.app.plugins) {
|
||||||
protyle.app.plugins.forEach((plugin: any) => {
|
protyle.app.plugins.forEach((plugin: any) => {
|
||||||
plugin.eventBus.emit("code-language-update", eventDetail);
|
plugin.eventBus.emit("code-language-update", eventDetail);
|
||||||
|
|
@ -1247,18 +1256,13 @@ export class Toolbar {
|
||||||
}
|
}
|
||||||
|
|
||||||
hljsLanguages = eventDetail.languages;
|
hljsLanguages = eventDetail.languages;
|
||||||
hljsLanguages.forEach((item, index) => {
|
hljsLanguages.forEach((item) => {
|
||||||
html += `<div class="b3-list-item${index === 0 ? " b3-list-item--focus" : ""}">${item}</div>`;
|
html += `<div data-id="${item}" class="b3-list-item">${item}</div>`;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.subElement.style.width = "";
|
listElement.innerHTML = html;
|
||||||
this.subElement.style.padding = "";
|
listElement.firstElementChild.nextElementSibling.classList.add("b3-list-item--focus");
|
||||||
this.subElement.innerHTML = `<div class="fn__flex-column" style="max-height:50vh">
|
|
||||||
<input placeholder="${window.siyuan.languages.search}" style="margin: 0 8px 4px 8px" class="b3-text-field"/>
|
|
||||||
<div class="b3-list fn__flex-1 b3-list--background" style="position: relative">${html}</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
const listElement = this.subElement.lastElementChild.lastElementChild as HTMLElement;
|
|
||||||
const inputElement = this.subElement.querySelector("input");
|
const inputElement = this.subElement.querySelector("input");
|
||||||
inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
|
inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
@ -1269,7 +1273,6 @@ export class Toolbar {
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
this.updateLanguage(languageElements, protyle, this.subElement.querySelector(".b3-list-item--focus").textContent);
|
this.updateLanguage(languageElements, protyle, this.subElement.querySelector(".b3-list-item--focus").textContent);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
|
|
@ -1277,55 +1280,75 @@ export class Toolbar {
|
||||||
focusByRange(this.range);
|
focusByRange(this.range);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const highlightText = (text: string, search: string) => {
|
||||||
|
// 转义正则特殊字符
|
||||||
|
const escapedSearch = search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||||
|
// 创建不区分大小写的正则表达式
|
||||||
|
const regex = new RegExp(escapedSearch, "gi");
|
||||||
|
// 替换匹配内容并保留原始大小写
|
||||||
|
return text.replace(regex, match =>
|
||||||
|
`<b>${match}</b>`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
inputElement.addEventListener("input", (event) => {
|
inputElement.addEventListener("input", (event) => {
|
||||||
const lowerCaseValue = inputElement.value.toLowerCase();
|
const value = inputElement.value.trim();
|
||||||
const matchLanguages = hljsLanguages.filter(item => item.includes(lowerCaseValue));
|
let matchLanguages;
|
||||||
let html = "";
|
let html = `<div data-id="clearLanguage" class="b3-list-item">${window.siyuan.languages.clear}</div>`;
|
||||||
// sort
|
let isMatchLanguages = false;
|
||||||
let matchInput = false;
|
// Sort
|
||||||
if (lowerCaseValue) {
|
if (value) {
|
||||||
matchLanguages.sort((a, b) => {
|
const lowerCaseValue = value.toLowerCase();
|
||||||
if (a.startsWith(lowerCaseValue) && b.startsWith(lowerCaseValue)) {
|
matchLanguages = hljsLanguages.filter(
|
||||||
if (a.length < b.length) {
|
item => item.toLowerCase().includes(lowerCaseValue)
|
||||||
return -1;
|
).sort((a, b) => {
|
||||||
} else if (a.length === b.length) {
|
// 不区分大小写
|
||||||
return 0;
|
const aStartsWith = a.toLowerCase().startsWith(lowerCaseValue);
|
||||||
} else {
|
const bStartsWith = b.toLowerCase().startsWith(lowerCaseValue);
|
||||||
return 1;
|
|
||||||
}
|
// 两者都匹配开头时,短字符串优先
|
||||||
} else if (a.startsWith(lowerCaseValue)) {
|
if (aStartsWith && bStartsWith) return a.length - b.length;
|
||||||
return -1;
|
if (aStartsWith) return -1;
|
||||||
} else if (b.startsWith(lowerCaseValue)) {
|
if (bStartsWith) return 1;
|
||||||
return 1;
|
|
||||||
} else {
|
// 都不匹配时保持原顺序
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (window.hljs?.getLanguage(value)) {
|
||||||
|
// Default languages and their aliases
|
||||||
|
matchLanguages = [value].concat(matchLanguages.filter(item => item !== value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const eventDetail = {languages: matchLanguages};
|
const eventDetail = {languages: value ? matchLanguages : hljsLanguages, type: "match", value, listElement};
|
||||||
if (protyle.app && protyle.app.plugins) {
|
if (protyle.app && protyle.app.plugins) {
|
||||||
protyle.app.plugins.forEach((plugin: any) => {
|
protyle.app.plugins.forEach((plugin: any) => {
|
||||||
plugin.eventBus.emit("code-language-update", eventDetail);
|
plugin.eventBus.emit("code-language-update", eventDetail);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
matchLanguages.forEach((item) => {
|
matchLanguages = eventDetail.languages;
|
||||||
if (inputElement.value === item) {
|
if (value) {
|
||||||
matchInput = true;
|
matchLanguages.forEach((item) => {
|
||||||
}
|
if (value === item) {
|
||||||
html += `<div class="b3-list-item">${item.replace(lowerCaseValue, "<b>" + lowerCaseValue + "</b>")}</div>`;
|
isMatchLanguages = true;
|
||||||
});
|
html += `<div data-id="${item}" class="b3-list-item"><b>${item}</b></div>`;
|
||||||
if (inputElement.value.trim() && !matchInput) {
|
} else {
|
||||||
html = `<div class="b3-list-item"><b>${escapeHtml(inputElement.value.replace(/`| /g, "_"))}</b></div>${html}`;
|
html += `<div data-id="${item}" class="b3-list-item">${highlightText(item, value)}</div>`;
|
||||||
}
|
}
|
||||||
html = `<div class="b3-list-item">${window.siyuan.languages.clear}</div>` + html;
|
});
|
||||||
listElement.innerHTML = html;
|
|
||||||
if (listElement.childElementCount > 2 && !matchInput && inputElement.value.trim()) {
|
|
||||||
listElement.firstElementChild.nextElementSibling.nextElementSibling.classList.add("b3-list-item--focus");
|
|
||||||
} else {
|
} else {
|
||||||
listElement.firstElementChild.nextElementSibling.classList.add("b3-list-item--focus");
|
matchLanguages.forEach((item) => {
|
||||||
|
html += `<div data-id="${item}" class="b3-list-item">${item}</div>`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
if (value && !isMatchLanguages) {
|
||||||
|
html += `<div data-id="customLanguage" class="b3-list-item"><b>${escapeHtml(value.replace(/`| /g, "_"))}</b></div>`;
|
||||||
|
}
|
||||||
|
listElement.innerHTML = html;
|
||||||
|
listElement.firstElementChild.nextElementSibling.classList.add("b3-list-item--focus");
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
});
|
});
|
||||||
listElement.addEventListener("click", (event) => {
|
listElement.addEventListener("click", (event) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue