ChatGPT/scripts/cmd.js

343 lines
10 KiB
JavaScript
Raw Normal View History

2023-05-18 07:32:32 +00:00
/**
* @name cmd.js
* @version 0.1.0
* @url https://github.com/lencx/ChatGPT/tree/main/scripts/cmd.js
*/
2023-01-08 04:28:54 +00:00
function init() {
2023-01-08 04:28:54 +00:00
const styleDom = document.createElement('style');
styleDom.innerHTML = `form {
position: relative;
}
.chat-model-cmd-list {
position: absolute;
bottom: 60px;
max-height: 100px;
overflow: auto;
z-index: 9999;
}
.chat-model-cmd-list>div {
border: solid 2px rgba(80,80,80,.3);
border-radius: 5px;
background-color: #fff;
}
html.dark .chat-model-cmd-list>div {
background-color: #4a4a4a;
}
html.dark .chat-model-cmd-list .cmd-item {
border-color: #666;
}
html.dark .chat-model-cmd-list .cmd-item b {
color: #e8e8e8;
}
html.dark .chat-model-cmd-list .cmd-item i {
color: #999;
}
html.dark .chat-model-cmd-list .cmd-item.selected {
background: rgba(59,130,246,.5);
}
.chat-model-cmd-list .cmd-item {
font-size: 12px;
border-bottom: solid 1px rgba(80,80,80,.2);
padding: 2px 4px;
display: flex;
user-select: none;
cursor: pointer;
}
.chat-model-cmd-list .cmd-item:last-child {
border-bottom: none;
}
.chat-model-cmd-list .cmd-item.selected {
background: rgba(59,130,246,.3);
}
.chat-model-cmd-list .cmd-item b {
display: inline-block;
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
border-radius: 4px;
margin-right: 10px;
color: #2a2a2a;
}
.chat-model-cmd-list .cmd-item i {
width: 100%;
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: right;
color: #888;
}
.chatappico {
width: 20px;
height: 20px;
}
2023-01-10 02:45:17 +00:00
.chatappico.pdf, .chatappico.md {
width: 22px;
height: 22px;
2023-01-08 04:28:54 +00:00
}
2023-02-01 15:48:35 +00:00
.chatappico.copy {
width: 16px;
height: 16px;
}
2023-02-02 17:30:03 +00:00
.chatappico.cpok {
width: 16px;
height: 16px;
}
2023-03-05 03:45:52 +00:00
.chatappico.refresh {
width: 22px;
height: 22px;
}
#download-markdown-button,
#download-png-button,
#download-pdf-button,
#refresh-page-button {
border: none;
}
2023-01-08 04:28:54 +00:00
@media screen and (max-width: 767px) {
#download-png-button, #download-pdf-button, #download-html-button {
display: none;
}
}
`;
document.head.append(styleDom);
if (window.formInterval) {
clearInterval(window.formInterval);
}
window.formInterval = setInterval(() => {
2023-05-18 07:32:32 +00:00
const form = document.querySelector('form textarea');
2023-01-08 04:28:54 +00:00
if (!form) return;
clearInterval(window.formInterval);
cmdTip();
new MutationObserver(function (mutationsList) {
for (const mutation of mutationsList) {
if (mutation.target.getAttribute('id') === '__next') {
initDom();
cmdTip();
}
if (mutation.target.getAttribute('class') === 'chat-model-cmd-list') {
// The `chatgpt prompt` fill can be done by clicking on the event.
2023-05-18 07:32:32 +00:00
const searchDom = document.querySelector('form .chat-model-cmd-list>div');
const searchInput = document.querySelector('form textarea');
if (!searchDom) return;
searchDom.addEventListener('click', (event) => {
2023-05-18 07:32:32 +00:00
const item = event.target.closest('div');
if (item) {
const val = decodeURIComponent(item.getAttribute('data-prompt'));
searchInput.value = val;
document.querySelector('form textarea').focus();
initDom();
}
});
}
}
}).observe(document.body, {
childList: true,
subtree: true,
});
}, 300);
}
2023-01-08 04:28:54 +00:00
async function cmdTip() {
initDom();
2023-05-18 07:32:32 +00:00
const chatModelJson = (await invoke('get_chat_model_cmd')) || {};
2023-01-08 04:28:54 +00:00
const data = chatModelJson.data;
if (data.length <= 0) return;
let modelDom = document.querySelector('.chat-model-cmd-list');
if (!modelDom) {
const dom = document.createElement('div');
dom.classList.add('chat-model-cmd-list');
document.querySelector('form').appendChild(dom);
modelDom = document.querySelector('.chat-model-cmd-list');
2023-01-08 04:28:54 +00:00
// fix: tray window
if (__TAURI_METADATA__.__currentWindow.label === 'tray') {
modelDom.style.bottom = '54px';
2023-01-08 04:28:54 +00:00
}
2023-05-18 07:32:32 +00:00
const itemDom = (v) =>
`<div class="cmd-item" title="${v.prompt}" data-cmd="${
v.cmd
}" data-prompt="${encodeURIComponent(v.prompt)}"><b title="${v.cmd}">/${v.cmd}</b><i>${
v.act
}</i></div>`;
const renderList = (v) => {
initDom();
modelDom.innerHTML = `<div>${v.map(itemDom).join('')}</div>`;
window.__CHAT_MODEL_CMD_PROMPT__ = v[0]?.prompt.trim();
window.__CHAT_MODEL_CMD__ = v[0]?.cmd.trim();
window.__cmd_list = modelDom.querySelectorAll('.cmd-item');
window.__cmd_index = 0;
window.__cmd_list[window.__cmd_index].classList.add('selected');
};
const setPrompt = (v = '') => {
if (v.trim()) {
2023-05-18 07:32:32 +00:00
window.__CHAT_MODEL_CMD_PROMPT__ = window.__CHAT_MODEL_CMD_PROMPT__?.replace(
/\{([^{}]*)\}/,
`{${v.trim()}}`,
);
}
2023-05-18 07:32:32 +00:00
};
const searchInput = document.querySelector('form textarea');
2023-01-08 04:28:54 +00:00
// Enter a command starting with `/` and press a space to automatically fill `chatgpt prompt`.
// If more than one command appears in the search results, the first one will be used by default.
function cmdKeydown(event) {
if (!window.__CHAT_MODEL_CMD_PROMPT__) {
2023-05-18 07:32:32 +00:00
if (
!event.shiftKey &&
event.keyCode === 13 &&
__TAURI_METADATA__.__currentWindow.label === 'tray'
) {
const btn = document.querySelector('form button');
if (btn) btn.click();
event.preventDefault();
}
return;
}
2023-01-08 04:28:54 +00:00
// ------------------ Keyboard scrolling (ArrowUp | ArrowDown) --------------------------
2023-05-18 07:32:32 +00:00
if (event.keyCode === 38 && window.__cmd_index > 0) {
// ArrowUp
window.__cmd_list[window.__cmd_index].classList.remove('selected');
window.__cmd_index = window.__cmd_index - 1;
window.__cmd_list[window.__cmd_index].classList.add('selected');
2023-05-18 07:32:32 +00:00
window.__CHAT_MODEL_CMD_PROMPT__ = decodeURIComponent(
window.__cmd_list[window.__cmd_index].getAttribute('data-prompt'),
);
searchInput.value = `/${window.__cmd_list[window.__cmd_index].getAttribute('data-cmd')}`;
event.preventDefault();
}
2023-01-08 04:28:54 +00:00
2023-05-18 07:32:32 +00:00
if (event.keyCode === 40 && window.__cmd_index < window.__cmd_list.length - 1) {
// ArrowDown
window.__cmd_list[window.__cmd_index].classList.remove('selected');
window.__cmd_index = window.__cmd_index + 1;
window.__cmd_list[window.__cmd_index].classList.add('selected');
2023-05-18 07:32:32 +00:00
window.__CHAT_MODEL_CMD_PROMPT__ = decodeURIComponent(
window.__cmd_list[window.__cmd_index].getAttribute('data-prompt'),
);
searchInput.value = `/${window.__cmd_list[window.__cmd_index].getAttribute('data-cmd')}`;
event.preventDefault();
}
2023-01-08 04:28:54 +00:00
const containerHeight = modelDom.offsetHeight;
const itemHeight = window.__cmd_list[0].offsetHeight + 1;
2023-01-08 04:28:54 +00:00
const itemTop = window.__cmd_list[window.__cmd_index].offsetTop;
const itemBottom = itemTop + itemHeight;
if (itemTop < modelDom.scrollTop || itemBottom > modelDom.scrollTop + containerHeight) {
modelDom.scrollTop = itemTop;
2023-01-08 04:28:54 +00:00
}
// ------------------ TAB key replaces `{q}` tag content -------------------------------
// feat: https://github.com/lencx/ChatGPT/issues/54
if (event.keyCode === 9 && !window.__CHAT_MODEL_STATUS__) {
const strGroup = window.__CHAT_MODEL_CMD_PROMPT__.match(/\{([^{}]*)\}/) || [];
if (strGroup[1]) {
searchInput.value = `/${window.__CHAT_MODEL_CMD__}` + ` {${strGroup[1]}}` + ' |-> ';
window.__CHAT_MODEL_STATUS__ = 1;
} else {
searchInput.value = window.__CHAT_MODEL_CMD_PROMPT__;
initDom();
}
event.preventDefault();
2023-01-08 04:28:54 +00:00
}
2023-05-18 07:32:32 +00:00
if (window.__CHAT_MODEL_STATUS__ === 1 && event.keyCode === 9) {
// TAB
const data = searchInput.value.split('|->');
if (data[1]?.trim()) {
setPrompt(data[1]);
window.__CHAT_MODEL_STATUS__ = 2;
}
event.preventDefault();
}
2023-01-08 04:28:54 +00:00
// input text
2023-05-18 07:32:32 +00:00
if (window.__CHAT_MODEL_STATUS__ === 2 && event.keyCode === 9) {
// TAB
searchInput.value = window.__CHAT_MODEL_CMD_PROMPT__;
modelDom.innerHTML = '';
delete window.__CHAT_MODEL_STATUS__;
event.preventDefault();
}
2023-01-08 04:28:54 +00:00
// ------------------ type in a space to complete the fill ------------------------------------
if (event.keyCode === 32) {
searchInput.value = window.__CHAT_MODEL_CMD_PROMPT__;
modelDom.innerHTML = '';
delete window.__CHAT_MODEL_CMD_PROMPT__;
}
2023-01-08 04:28:54 +00:00
// ------------------ send --------------------------------------------------------------------
2023-05-18 07:32:32 +00:00
if (event.keyCode === 13 && window.__CHAT_MODEL_CMD_PROMPT__) {
// Enter
const data = searchInput.value.split('|->');
setPrompt(data[1]);
searchInput.value = window.__CHAT_MODEL_CMD_PROMPT__;
2023-01-08 04:28:54 +00:00
initDom();
2023-03-01 11:21:59 +00:00
event.preventDefault();
}
2023-01-08 04:28:54 +00:00
}
searchInput.removeEventListener('keydown', cmdKeydown, { capture: true });
searchInput.addEventListener('keydown', cmdKeydown, { capture: true });
2023-01-08 04:28:54 +00:00
function cmdInput() {
if (searchInput.value === '') {
initDom();
}
2023-01-08 04:28:54 +00:00
if (window.__CHAT_MODEL_STATUS__) return;
2023-01-08 04:28:54 +00:00
const query = searchInput.value;
if (!query || !/^\//.test(query)) {
initDom();
return;
}
2023-01-08 04:28:54 +00:00
// all cmd result
if (query === '/') {
renderList(data);
return;
}
2023-05-18 07:32:32 +00:00
const result = data.filter((i) => new RegExp(query.substring(1)).test(i.cmd));
if (result.length > 0) {
renderList(result);
} else {
initDom();
}
2023-01-08 04:28:54 +00:00
}
searchInput.removeEventListener('input', cmdInput);
searchInput.addEventListener('input', cmdInput);
}
}
2023-01-08 04:28:54 +00:00
function initDom() {
const modelDom = document.querySelector('.chat-model-cmd-list');
if (modelDom) {
modelDom.innerHTML = '';
2023-01-08 04:28:54 +00:00
}
delete window.__CHAT_MODEL_CMD_PROMPT__;
delete window.__CHAT_MODEL_CMD__;
delete window.__CHAT_MODEL_STATUS__;
delete window.__cmd_list;
delete window.__cmd_index;
2023-01-08 04:28:54 +00:00
}
2023-05-18 07:32:32 +00:00
if (document.readyState === 'complete' || document.readyState === 'interactive') {
init();
} else {
2023-05-18 07:32:32 +00:00
document.addEventListener('DOMContentLoaded', init);
}