@@ -359,6 +359,12 @@ async def serve_ui():
359359 font-size:10px;font-weight:600;margin-right:6px;
360360 background:rgba(159,122,234,0.15);color:var(--accent-purple);
361361}
362+ .title-lang-item{
363+ margin-bottom:4px;
364+ }
365+ .title-lang-item:last-child{
366+ margin-bottom:0;
367+ }
362368.ctx-search-no-results{
363369 padding:12px;text-align:center;font-size:12px;color:var(--text-muted);
364370}
@@ -854,7 +860,12 @@ async def serve_ui():
854860 let type = 'content';
855861 if (c.pecha_text_id) type = 'search';
856862 else if (c.file_url) type = 'file';
857- addContextEntry(type, {content: c.content, file_url: c.file_url, pecha_title: c.pecha_title, pecha_text_id: c.pecha_text_id});
863+ addContextEntry(type, {
864+ content: c.content,
865+ file_url: c.file_url,
866+ pecha_title: c.pecha_title,
867+ pecha_text_id: c.pecha_text_id
868+ });
858869 });
859870 }
860871 document.getElementById('modalOverlay').classList.add('active');
@@ -920,6 +931,20 @@ async def serve_ui():
920931 renderFileField(fieldArea, data.file_url || '');
921932 } else if (selectedType === 'search') {
922933 renderSearchField(fieldArea, data.pecha_title || '', data.pecha_text_id || '');
934+ // If editing and has content, create a mock search result with the content
935+ if (data.content && data.pecha_title && data.pecha_text_id) {
936+ const contentDataScript = document.createElement('script');
937+ contentDataScript.type = 'application/json';
938+ contentDataScript.className = 'ctx-pecha-content-data';
939+ // Create a single item array with the content
940+ contentDataScript.textContent = JSON.stringify([{
941+ id: data.pecha_text_id,
942+ content: data.content,
943+ type: 'text',
944+ source: 'pecha'
945+ }]);
946+ fieldArea.appendChild(contentDataScript);
947+ }
923948 }
924949}
925950
@@ -1026,7 +1051,7 @@ async def serve_ui():
10261051 `;
10271052 if (title && textId) {
10281053 const tagsDiv = container.querySelector('.pecha-tags');
1029- addPechaTag(tagsDiv, container, title, textId);
1054+ addPechaTag(tagsDiv, container, title, textId, null );
10301055 }
10311056}
10321057
@@ -1044,24 +1069,19 @@ async def serve_ui():
10441069 resultsDiv.innerHTML = '<div class="ctx-search-no-results"><span class="spinner"></span> Searching...</div>';
10451070
10461071 try {
1047- const r = await fetch('https://search.buddhistai.tools/search', {
1048- method: 'POST',
1049- headers: {'Content-Type':'application/json'},
1050- body: JSON.stringify({limit:10, query:query, return_text:true, search_type:'exact'})
1051- });
1072+ const r = await fetch('https://api-aq25662yyq-uc.a.run.app/v2/texts?limit=20&offset=0&title=' + encodeURIComponent(query));
10521073 if (!r.ok) throw new Error('Search failed');
1053- const data = await r.json();
1054- const results = data.results || [];
1074+ const results = await r.json();
10551075 if (!results.length) {
10561076 resultsDiv.innerHTML = '<div class="ctx-search-no-results">No results found</div>';
10571077 } else {
1058- results.forEach(item => { _searchResultsCache[item.id] = item.entity?.text || ''; });
10591078 resultsDiv.innerHTML = results.map(item => {
1060- const text = item.entity?.text || '';
1061- const lang = item.entity?.language || '';
1062- const displayText = text.length > 150 ? text.slice(0,150) + '...' : text;
1079+ const title = item.title || {};
1080+ const titleTexts = Object.entries(title).map(([lang, text]) =>
1081+ '<div class="title-lang-item"><span class="result-lang">' + esc(lang) + '</span>: ' + esc(text.length > 100 ? text.slice(0,100) + '...' : text) + '</div>'
1082+ ).join('');
10631083 return '<div class="ctx-search-result-item" data-result-id="' + esc(item.id) + '" onclick="selectSearchResult(this)">'
1064- + '<span class="result-lang">' + esc(lang) + '</span>' + esc(displayText)
1084+ + titleTexts
10651085 + '</div>';
10661086 }).join('');
10671087 }
@@ -1073,29 +1093,89 @@ async def serve_ui():
10731093 }
10741094}
10751095
1076- function selectSearchResult(el) {
1096+ async function selectSearchResult(el) {
10771097 const id = el.getAttribute('data-result-id');
1078- const fullText = _searchResultsCache[id] || '';
10791098 const entry = el.closest('.context-entry');
10801099 const fieldArea = entry.querySelector('.ctx-field-area');
10811100 const tagsDiv = fieldArea.querySelector('.pecha-tags');
10821101 const titleInput = fieldArea.querySelector('.ctx-pecha-title');
10831102 const idInput = fieldArea.querySelector('.ctx-pecha-text-id');
10841103 const resultsDiv = entry.querySelector('.ctx-search-results');
10851104
1086- const displayTitle = fullText.length > 80 ? fullText.slice(0,80) + '...' : fullText;
1087- titleInput.value = displayTitle;
1088- idInput.value = id;
1089- resultsDiv.style.display = 'none';
1090-
1091- tagsDiv.innerHTML = '';
1092- addPechaTag(tagsDiv, fieldArea, displayTitle, id);
1105+ const titleText = el.textContent.trim();
1106+ const displayTitle = titleText.length > 80 ? titleText.slice(0,80) + '...' : titleText;
1107+
1108+ // Show loading state
1109+ el.innerHTML = '<span class="spinner" style="width:12px;height:12px;border-width:2px"></span> Loading content...';
1110+ el.style.pointerEvents = 'none';
1111+
1112+ try {
1113+ // Call the search endpoint to fetch content
1114+ const r = await fetch(API_BASE + '/search/' + encodeURIComponent(id));
1115+ if (!r.ok) throw new Error('Failed to fetch content');
1116+ const searchData = await r.json();
1117+
1118+ // Store both the title and the fetched content
1119+ titleInput.value = displayTitle;
1120+ idInput.value = id;
1121+
1122+ // Store content data as JSON in a script tag to avoid HTML escaping issues
1123+ let contentScript = fieldArea.querySelector('.ctx-pecha-content-data');
1124+ if (!contentScript) {
1125+ contentScript = document.createElement('script');
1126+ contentScript.type = 'application/json';
1127+ contentScript.className = 'ctx-pecha-content-data';
1128+ fieldArea.appendChild(contentScript);
1129+ }
1130+ contentScript.textContent = JSON.stringify(searchData || []);
1131+
1132+ resultsDiv.style.display = 'none';
1133+ tagsDiv.innerHTML = '';
1134+ addPechaTag(tagsDiv, fieldArea, displayTitle, id, searchData);
1135+
1136+ toast('Content loaded successfully! (' + (searchData?.length || 0) + ' items)', 'success');
1137+ } catch(e) {
1138+ toast('Error loading content: ' + e.message, 'error');
1139+ el.innerHTML = displayTitle;
1140+ el.style.pointerEvents = '';
1141+ }
10931142}
10941143
1095- function addPechaTag(tagsDiv, fieldArea, title, id) {
1096- const tag = document.createElement('span');
1097- tag.className = 'pecha-tag';
1098- tag.innerHTML = `<span class="pecha-tag-text">${esc(title)}</span><button class="pecha-tag-remove" onclick="removePechaTag(this)">×</button>`;
1144+ function addPechaTag(tagsDiv, fieldArea, title, id, searchData) {
1145+ const tag = document.createElement('div');
1146+ tag.style.cssText = 'margin-top:8px';
1147+
1148+ // Add main tag
1149+ tag.innerHTML = `
1150+ <div class="pecha-tag">
1151+ <span class="pecha-tag-text">${esc(title)}</span>
1152+ <button class="pecha-tag-remove" onclick="removePechaTag(this)">×</button>
1153+ </div>
1154+ `;
1155+
1156+ // If we have search data, show the content items
1157+ if (searchData && searchData.length > 0) {
1158+ const contentList = document.createElement('div');
1159+ contentList.style.cssText = 'margin-top:8px;display:flex;flex-direction:column;gap:8px';
1160+
1161+ searchData.forEach((item, idx) => {
1162+ const contentPreview = (item.content || '').substring(0, 150);
1163+ const itemDiv = document.createElement('div');
1164+ itemDiv.style.cssText = 'padding:8px 10px;background:var(--bg-input);border:1px solid var(--border);border-radius:var(--radius-xs);font-size:12px';
1165+ itemDiv.innerHTML = `
1166+ <div style="font-weight:600;color:var(--accent-purple);margin-bottom:4px">
1167+ ${esc(item.type || 'Content')} - ${esc(item.source || 'Unknown')}
1168+ </div>
1169+ <div style="color:var(--text-secondary);line-height:1.5">
1170+ ${esc(contentPreview)}${contentPreview.length >= 150 ? '...' : ''}
1171+ </div>
1172+ `;
1173+ contentList.appendChild(itemDiv);
1174+ });
1175+
1176+ tag.appendChild(contentList);
1177+ }
1178+
10991179 tagsDiv.appendChild(tag);
11001180}
11011181
@@ -1104,7 +1184,18 @@ async def serve_ui():
11041184 const fieldArea = entry.querySelector('.ctx-field-area');
11051185 fieldArea.querySelector('.ctx-pecha-title').value = '';
11061186 fieldArea.querySelector('.ctx-pecha-text-id').value = '';
1107- btn.closest('.pecha-tag').remove();
1187+
1188+ // Remove the content data script if it exists
1189+ const contentDataScript = fieldArea.querySelector('.ctx-pecha-content-data');
1190+ if (contentDataScript) {
1191+ contentDataScript.remove();
1192+ }
1193+
1194+ // Clear the pecha tags div
1195+ const tagsDiv = fieldArea.querySelector('.pecha-tags');
1196+ if (tagsDiv) {
1197+ tagsDiv.innerHTML = '';
1198+ }
11081199}
11091200
11101201function getContextsFromForm() {
@@ -1121,7 +1212,39 @@ async def serve_ui():
11211212 } else if (type === 'search') {
11221213 const pecha_title = e.querySelector('.ctx-pecha-title')?.value.trim();
11231214 const pecha_text_id = e.querySelector('.ctx-pecha-text-id')?.value.trim();
1124- if (pecha_title && pecha_text_id) contexts.push({content:null, file_url:null, pecha_title, pecha_text_id});
1215+ const contentDataScript = e.querySelector('.ctx-pecha-content-data');
1216+
1217+ if (pecha_title && pecha_text_id) {
1218+ // Parse the stored JSON data
1219+ let searchData = [];
1220+ if (contentDataScript) {
1221+ try {
1222+ searchData = JSON.parse(contentDataScript.textContent || '[]');
1223+ } catch(err) {
1224+ console.error('Failed to parse search data', err);
1225+ }
1226+ }
1227+
1228+ // Create separate context entries for each search result
1229+ if (searchData.length > 0) {
1230+ searchData.forEach(item => {
1231+ contexts.push({
1232+ content: item.content || null,
1233+ file_url: null,
1234+ pecha_title: pecha_title,
1235+ pecha_text_id: pecha_text_id
1236+ });
1237+ });
1238+ } else {
1239+ // No content loaded yet, just store the metadata
1240+ contexts.push({
1241+ content: null,
1242+ file_url: null,
1243+ pecha_title: pecha_title,
1244+ pecha_text_id: pecha_text_id
1245+ });
1246+ }
1247+ }
11251248 }
11261249 });
11271250 return contexts;
0 commit comments