PropertyTable 생성

This commit is contained in:
현성필
2024-01-19 21:10:57 +09:00
parent dba414cb4a
commit 924196b629
33 changed files with 1067 additions and 368 deletions
+132 -67
View File
@@ -1,90 +1,59 @@
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 || '';
class EditableInputModel {
constructor(value = '') {
this.value = value;
}
init(element, callback) {
this.element = element;
this.element.innerHTML = this.render();
this.attachEventListeners(callback);
setValue(newValue) {
this.value = newValue;
}
val(newValue) {
if (newValue !== undefined) {
this.value = newValue;
this.updateUI();
}
getValue() {
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;
class EditableInputView {
constructor(model, editableInput) {
this.model = model;
this.editableInput = editableInput;
}
render() {
let contentHtml = this.value ? this.renderContent(this.parseContent(this.value)) : '​';
render(element) {
this.element = element;
this.element.innerHTML = this.generateInputHtml();
this.editableDiv = this.element.querySelector('.editableInputContent');
this.attachEventListeners();
}
generateInputHtml() {
let contentHtml = this.model.getValue() ? this.renderContent(this.parseContent(this.model.getValue())) : '​';
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>
`;
<div contenteditable="true" class="editableInputContent form-control" data-value="${this.model.getValue()}">
${contentHtml}
</div>
`;
}
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);
attachEventListeners() {
this.editableDiv.addEventListener('input', (event) => {
this.editableInput.controller.handleInput(this.editableDiv);
if (this.editableInput.controller.additionalCallback) {
this.editableInput.controller.additionalCallback(this.model.getValue());
}
});
}
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;
updateUI() {
let content = this.model.getValue();
if (content) {
this.editableDiv.innerHTML = this.renderContent(this.parseContent(content));
} else {
editableDiv.innerHTML = this.renderContent(content);
this.editableDiv.innerHTML = '&#8203;'; // Insert a zero-width space
}
this.restoreCursor(editableDiv, cursor);
this.editableDiv.setAttribute('data-value', content);
}
renderContent(contentArray) {
let content = '';
contentArray.forEach((item) => {
@@ -122,6 +91,20 @@ class EditableInput {
return returnStringArray;
}
}
class EditableInputController {
constructor(model, view) {
this.model = model;
this.view = view;
}
init(element, callback) {
this.view.render(element);
this.additionalCallback = callback;
}
getCurrentCursor(element) {
const selection = window.getSelection();
@@ -134,6 +117,53 @@ class EditableInput {
return preCaretRange.toString().trim().length;
}
handleInput(editableDiv) {
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.model.setValue(content.join(''));
// Optionally, update the view if needed
this.view.updateUI();
this.restoreCursor(editableDiv, cursor);
}
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;
}
restoreCursor(element, position) {
const selection = window.getSelection();
const range = document.createRange();
@@ -167,7 +197,42 @@ class EditableInput {
selection.removeAllRanges();
selection.addRange(range);
}
}
class EditableInput {
constructor(options = {}) {
// Initialize the model with the value
this.model = new EditableInputModel(options.value || '');
// Create the view and controller, passing the model to them
this.view = new EditableInputView(this.model, this);
this.controller = new EditableInputController(this.model, this.view);
// Additional properties as required
this.name = options.name || '';
this.id = options.id || '';
this.class = options.class || 'form-control';
this.placeholder = options.placeholder || '';
}
init(element, callback) {
// Initialize the controller with the DOM element
this.controller.init(element, callback);
}
getValue() {
// Delegate to the model
return this.model.getValue();
}
setValue(newValue) {
// Delegate to the model and update the view
this.model.setValue(newValue);
this.view.updateUI();
}
// Any additional methods required for interaction with this component
}
export default EditableInput;