1 directories, 28 files

tinai

Home / testing / ai / tinai
/**
 * class Context
 * Handles the display of context-related information.
 */
class Context {

	/**
	 * Initializes a new instance of the Context class.
	 * @param storage
	 * @param app_callbacks
	 */
	constructor(storage, app_callbacks) {
		this.storage = storage;
		this.app_callbacks = app_callbacks;
	}


	/**
	 * Renders the context view.
	 * @returns {string} HTML string for the context view.
	 */
	render() {
		let html = '<div class="div-scroll-container-inner">'

		html+='<h4>Topics</h4><hr><div id="topics-display-area">';
		html += this._generateTopicChipsHtml();
		html += '</div>';

		html += `
            <div class="add-topic-section" style="width: 100%;">
                <input type="text" id="new-topic-input" placeholder="Add new topic" style="width: 100%;box-sizing: border-box;margin: 4pt 0;"/>
                <div style="text-align: right;">
                	<button id="add-topic-button" style="min-width: 6em;">Add Topic</button>
                </div>
            </div>
        `;

		html += '<h4>Considerations</h4><hr><div id="considerations-display-area">';
		html += this._generateConsiderationsHtml();
		html += '</div>';

		html += `
            <div class="add-consideration-section" style="width: 100%;">
                <textarea id="new-consideration-input" class="prompt-style-input" style="margin-bottom: 0;" placeholder="Add new consideration"></textarea>
				<div style="text-align: right;">
                	<button id="add-consideration-button" style="min-width: 6em;">Add Consideration</button>
				</div>
            </div>
        `;

		html += '</div>';

		return html;
	}

	/**
	 * Generates the HTML for the topic chips or "No Topics" message.
	 * @returns {string} HTML string.
	 * @private
	 */
	_generateTopicChipsHtml() {
		const key_topics = this.storage.KEY_CONVERSATION_TOPICS;
		const conversation = this.storage.get_selected_conversation();
		if (conversation && conversation[key_topics] && conversation[key_topics].length > 0) {
			let chipsHtml = '<div id="topic-chips" class="div-options-chips">';
			conversation[key_topics].forEach(topic => {
				chipsHtml += `
                <span class="span-option-chip" data-topic="${topic}">
                    ${topic}
                    <button class="delete-topic-button" data-topic="${topic}" style="padding: 0;height: 1.2em;line-height: 0;">&times;</button>
                </span>`;
			});
			chipsHtml += '</div>';
			return chipsHtml;
		} else {
			return '<p id="no-topics-message">No Topics</p>';
		}
	}

	_generateConsiderationsHtml() {
		const key_considerations = this.storage.KEY_CONVERSATION_CONSIDERATIONS;
		const conversation = this.storage.get_selected_conversation();
		if (conversation && conversation[key_considerations] && conversation[key_considerations].length > 0) {
			let considerationsHtml = '<div id="considerations-list">';
			conversation[key_considerations].forEach(consideration => {
				considerationsHtml += `
                <div class="consideration-item" data-consideration="${consideration}" style="display: flex; justify-content: space-between; align-items: center;">
                    <span style="flex-grow: 1;">${consideration}</span>
                    <button class="delete-consideration-button" data-consideration="${consideration}" style="min-width: 2em; text-align: center;">&times;</button>
                </div>`;
			});
			considerationsHtml += '</div>';
			return considerationsHtml;
		} else {
			return '<p id="no-considerations-message">No Considerations</p>';
		}
	}

	/**
	 * Dynamically updates the topic chips display in the DOM.
	 * @private
	 */
	_updateTopicChipsDisplay() {
		const topicsDisplayArea = document.getElementById('topics-display-area');
		if (topicsDisplayArea) {
			topicsDisplayArea.innerHTML = this._generateTopicChipsHtml();
			this._attachTopicChipListeners();
		}
	}

	_updateConsiderationsDisplay() {
		const considerationsDisplayArea = document.getElementById('considerations-display-area');
		if (considerationsDisplayArea) {
			considerationsDisplayArea.innerHTML = this._generateConsiderationsHtml();
			this._attachConsiderationClickListeners();
		}
	}

	_addTopicAction() {
		const newTopicInput = document.getElementById('new-topic-input');
		let newTopic = newTopicInput.value.trim();
		if (newTopic) {
			const wordCount = newTopic.split(' ').filter(word => word !== '').length;
			if (wordCount > 5) {
				alert('Topic can contain up to five words.');
				return;
			}
			const topicRegex = /^[a-zA-Z0-9\s'-]+$/;
			if (!topicRegex.test(newTopic)) {
				alert('Topic can only contain letters, numbers, spaces, hyphens, and apostrophes.');
				return;
			}
			this.addTopic(newTopic);
			newTopicInput.value = '';
			this._updateTopicChipsDisplay()
		}
	}

	_addConsiderationAction() {
		const newConsiderationInput = document.getElementById('new-consideration-input');
		let newConsideration = newConsiderationInput.value.trim();
		if (newConsideration) {
			if (newConsideration.includes('\n')) {
				alert('Considerations cannot contain new lines.');
				return;
			}
			const wordCount = newConsideration.split(' ').filter(word => word !== '').length;
			if (wordCount > 200) {
				alert('Consideration can be a maximum of 200 words.');
				return;
			}
			this.addConsideration(newConsideration);
			newConsiderationInput.value = '';
			this._updateConsiderationsDisplay();
		}
	}

	/**
	 * Attaches event listeners for the topic chips and add topic button.
	 */
	attachEventListeners() {
		this._attachTopicChipListeners();
		this._attachConsiderationClickListeners();

		const addTopicButton = document.getElementById('add-topic-button');
		if (addTopicButton) {
			addTopicButton.addEventListener('click', () => this._addTopicAction());
		}

		const newTopicInput = document.getElementById('new-topic-input');
		if (newTopicInput) {
			newTopicInput.addEventListener('keydown', (event) => {
				if (event.key === 'Enter') {
					event.preventDefault();
					this._addTopicAction();
				}
			});
		}

		const addConsiderationButton = document.getElementById('add-consideration-button');
		if (addConsiderationButton) {
			addConsiderationButton.addEventListener('click', () => this._addConsiderationAction());
		}

		const newConsiderationInput = document.getElementById('new-consideration-input');
		if (newConsiderationInput) {
			newConsiderationInput.addEventListener('keydown', (event) => {
				if (event.key === 'Enter') {
					event.preventDefault();
					this._addConsiderationAction();
				}
			});
		}
	}

	/**
	 * Attaches click listeners to the topic chips.
	 * @private
	 */
	_attachTopicChipListeners() {
		const topicChipsContainer = document.getElementById('topic-chips');
		if (topicChipsContainer) {
			topicChipsContainer.addEventListener('click', (event) => {
				if (event.target.classList.contains('delete-topic-button')) {
					const topicToDelete = event.target.dataset.topic;
					if (confirm(`Do you want to delete the topic "${topicToDelete}"?`)) {
						this.deleteTopic(topicToDelete);
					}
				}
			});
		}
	}

	_attachConsiderationClickListeners() {
		const considerationsContainer = document.getElementById('considerations-list');
		if (considerationsContainer) {
			considerationsContainer.addEventListener('click', (event) => {
				if (event.target.classList.contains('delete-consideration-button')) {
					const considerationToDelete = event.target.dataset.consideration;
					if (confirm(`Do you want to delete the consideration "${considerationToDelete}"?`)) {
						this.deleteConsideration(considerationToDelete);
					}
				}
			});
		}
	}

	/**
	 * Adds a new topic to the conversation.
	 * @param {string} topic The topic to add.
	 */
	addTopic(topic) {
		const config = this.storage.get_app_config();
		const guid = config[this.storage.KEY_CONFIG_SELECTED_CONVERSATION_GUID];

		if (guid) {
			this.storage.addTopicToConversation(guid, topic);
			this._updateTopicChipsDisplay();
		}
	}

	addConsideration(consideration) {
		const config = this.storage.get_app_config();
		const guid = config[this.storage.KEY_CONFIG_SELECTED_CONVERSATION_GUID];

		if (guid) {
			this.storage.addConsiderationToConversation(guid, consideration);
			this._updateConsiderationsDisplay();
		}
	}

	/**
	 * Deletes a topic from the conversation.
	 * @param {string} topic The topic to delete.
	 */
	deleteTopic(topic) {
		const config = this.storage.get_app_config();
		const guid = config[this.storage.KEY_CONFIG_SELECTED_CONVERSATION_GUID];

		if (guid) {
			this.storage.deleteTopicFromConversation(guid, topic);
			this._updateTopicChipsDisplay();
		}
	}

	deleteConsideration(consideration) {
		const config = this.storage.get_app_config();
		const guid = config[this.storage.KEY_CONFIG_SELECTED_CONVERSATION_GUID];

		if (guid) {
			this.storage.deleteConsiderationFromConversation(guid, consideration);
			this._updateConsiderationsDisplay();
		}
	}
}

export default Context;
🌐
context.js ×
Type: Web, text/plain
8.71 Kilobytes
Last Modified 2026-05-04 01:42:45
⬇ Download File