ApiTestManager 소스 추가

This commit is contained in:
현성필
2024-01-17 18:04:16 +09:00
parent 8a53e4dd23
commit dd4a24aa59
14 changed files with 9162 additions and 2 deletions
@@ -0,0 +1,173 @@
class EditableInput {
constructor(options = {}) {
this.value = options.value || '';
this.name = options.name || '';
this.id = options.id || '';
this.class = options.class || 'form-control';
this.placeholder = options.placeholder || '';
this.label = options.label || '';
}
init(element, callback) {
this.element = element;
this.element.innerHTML = this.render();
this.attachEventListeners(callback);
}
val(newValue) {
if (newValue !== undefined) {
this.value = newValue;
this.updateUI();
}
return this.value;
}
updateUI() {
const editableDiv = this.element.querySelector('.editableInputContent');
const hiddenInput = this.element.querySelector('input[type="hidden"]');
if (this.value) {
editableDiv.innerHTML = this.renderContent(this.parseContent(this.value));
} else {
editableDiv.innerHTML = '​'; // Insert a zero-width space
}
hiddenInput.value = this.value;
}
render() {
let contentHtml = this.value ? this.renderContent(this.parseContent(this.value)) : '​';
return `
<div contenteditable="true" class="editableInputContent ${this.class}" style="border-bottom-left-radius: 0; border-top-left-radius: 0;" placeholder="${this.placeholder}">
${contentHtml}
</div>
<input type="hidden" name="${this.name}" value="${this.value}" />
<label>${this.label}</label>
`;
}
attachEventListeners(callback) {
const editableDiv = this.element.querySelector('.editableInputContent');
const hiddenInput = this.element.querySelector('input[type="hidden"]');
editableDiv.addEventListener('input', (event) => {
this.handleInput(event, editableDiv, hiddenInput);
if (callback)
callback(event);
});
}
handleInput(event, editableDiv, hiddenInput) {
let cursor = this.getCurrentCursor(editableDiv);
let mergedString = Array.from(editableDiv.childNodes)
.filter(function(node) {
// Keep only SPAN elements and text nodes
return node.nodeName.toUpperCase() === 'SPAN' || node.nodeType === 3;
})
.map(node => {
return node.nodeType === 3 ? node.data.trim() : node.innerText.trim();
})
.join('');
let content = this.parseContent(mergedString);
this.value = content.join('');
hiddenInput.value = this.value;
if (!this.value) {
editableDiv.innerHTML = '&#8203;'; // Insert a zero-width space
cursor = 0;
} else {
editableDiv.innerHTML = this.renderContent(content);
}
this.restoreCursor(editableDiv, cursor);
}
renderContent(contentArray) {
let content = '';
contentArray.forEach((item) => {
if (item.startsWith('{{') && item.endsWith('}}')) {
content += `<span class="variable">${item}</span>`;
} else {
content += `<span class="text">${item}</span>`;
}
});
return content;
}
parseContent(inputString) {
let returnStringArray = [];
let regex = /{{.*?}}/g;
let lastIndex = 0;
inputString.replace(regex, (match, index) => {
// Add the string before the match
if (index > lastIndex) {
returnStringArray.push(inputString.slice(lastIndex, index));
}
// Add the matched string including the delimiters
returnStringArray.push(match);
// Update lastIndex for the next iteration
lastIndex = index + match.length;
});
// Add any remaining string after the last match
if (lastIndex < inputString.length) {
returnStringArray.push(inputString.slice(lastIndex));
}
return returnStringArray;
}
getCurrentCursor(element) {
const selection = window.getSelection();
if (selection.rangeCount === 0) return null;
const range = selection.getRangeAt(0);
const preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.endContainer, range.endOffset);
return preCaretRange.toString().trim().length;
}
restoreCursor(element, position) {
const selection = window.getSelection();
const range = document.createRange();
range.setStart(element, 0);
range.collapse(true);
const nodeStack = [element];
let node, foundStart = false, stop = false;
let charIndex = 0;
while (!stop && (node = nodeStack.pop())) {
if (node.nodeType === 3) {
const nextCharIndex = charIndex + node.length;
if (!foundStart && position >= charIndex && position <= nextCharIndex) {
range.setStart(node, position - charIndex);
foundStart = true;
}
if (foundStart && position >= charIndex && position <= nextCharIndex) {
range.setEnd(node, position - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
let i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
selection.removeAllRanges();
selection.addRange(range);
}
}
export default EditableInput;