diff --git a/assets/static/euskaditech-css/simple.css b/assets/static/euskaditech-css/simple.css
index c4ebdaa..39495ad 100644
--- a/assets/static/euskaditech-css/simple.css
+++ b/assets/static/euskaditech-css/simple.css
@@ -428,4 +428,19 @@ fieldset legend {
}
pre {
font-size: 15px;
+}
+.picto {
+ height: 125px;
+ width: 100px;
+ border: 2.5px solid black;
+ border-radius: 5px;
+ text-align: center;
+ background: white;
+ margin-bottom: 20px;
+ margin-left: auto;
+ margin-right: auto;
+}
+.picto b {
+ padding-top: 40px;
+ display: inline-block;
}
\ No newline at end of file
diff --git a/src/app_logic.js b/src/app_logic.js
index 1a63322..9fefc42 100644
--- a/src/app_logic.js
+++ b/src/app_logic.js
@@ -35,7 +35,7 @@ function open_page(params) {
PAGES[app].index();
return;
}
- PAGES[app].edit(path[1]);
+ PAGES[app].edit(path.slice(1).join(','));
}
function setUrlHash(hash) {
diff --git a/src/app_modules.js b/src/app_modules.js
index 6c3076f..14d6bf1 100644
--- a/src/app_modules.js
+++ b/src/app_modules.js
@@ -55,6 +55,368 @@ const debounce = (id, callback, wait, args) => {
return id;
};
+function TS_CreateSearchOverlay(parentEl, options = {}) {
+ const overlayId = safeuuid();
+ const panelId = safeuuid();
+ const inputId = safeuuid();
+ const closeId = safeuuid();
+ const clearId = safeuuid();
+
+ const overlay = document.createElement('div');
+ overlay.id = overlayId;
+ overlay.style.display = 'none';
+ overlay.style.position = 'fixed';
+ overlay.style.inset = '0';
+ overlay.style.background = 'rgba(0, 0, 0, 0.5)';
+ overlay.style.zIndex = '9999';
+ overlay.style.alignItems = 'center';
+ overlay.style.justifyContent = 'center';
+ overlay.style.padding = '16px';
+ overlay.innerHTML = html`
+
+
+
+
+
+
+
+ `;
+
+ const targetParent = parentEl || document.body;
+ targetParent.appendChild(overlay);
+
+ const inputEl = overlay.querySelector('#' + inputId);
+ const closeEl = overlay.querySelector('#' + closeId);
+ const clearEl = overlay.querySelector('#' + clearId);
+ const panelEl = overlay.querySelector('#' + panelId);
+
+ function open() {
+ overlay.style.display = 'flex';
+ inputEl.focus();
+ inputEl.select();
+ }
+
+ function close() {
+ overlay.style.display = 'none';
+ }
+
+ function setValue(value) {
+ inputEl.value = value || '';
+ }
+
+ function getValue() {
+ return inputEl.value || '';
+ }
+
+ inputEl.addEventListener('input', () => {
+ if (typeof options.onInput === 'function') {
+ options.onInput(getValue());
+ }
+ });
+
+ closeEl.addEventListener('click', close);
+ clearEl.addEventListener('click', () => {
+ setValue('');
+ if (typeof options.onInput === 'function') {
+ options.onInput('');
+ }
+ inputEl.focus();
+ });
+
+ overlay.addEventListener('click', (event) => {
+ if (event.target === overlay && panelEl) {
+ close();
+ }
+ });
+
+ return {
+ open,
+ close,
+ setValue,
+ getValue,
+ inputEl,
+ overlayEl: overlay,
+ };
+}
+
+function TS_InitOverlaySearch(container, openBtnId, badgeId, options = {}) {
+ const debounceId = options.debounceId || safeuuid();
+ const wait = options.wait || 200;
+ let currentValue = '';
+ const badgeEl = badgeId ? document.getElementById(badgeId) : null;
+ const overlay = TS_CreateSearchOverlay(container, {
+ placeholder: options.placeholder || 'Buscar...',
+ onInput: (value) => {
+ currentValue = (value || '').toLowerCase().trim();
+ if (badgeEl) {
+ badgeEl.textContent = currentValue ? `Filtro: "${currentValue}"` : '';
+ }
+ if (typeof options.onSearch === 'function') {
+ debounce(debounceId, options.onSearch, wait, [currentValue]);
+ }
+ },
+ });
+ if (openBtnId) {
+ const openBtn = document.getElementById(openBtnId);
+ if (openBtn) {
+ openBtn.addEventListener('click', () => overlay.open());
+ }
+ }
+ return {
+ open: overlay.open,
+ close: overlay.close,
+ setValue: overlay.setValue,
+ getValue: () => currentValue,
+ getValueRaw: overlay.getValue,
+ };
+}
+
+function TS_normalizePictoValue(value) {
+ if (!value) {
+ return { text: '', arasaacId: '' };
+ }
+ if (typeof value === 'string') {
+ return { text: value, arasaacId: '' };
+ }
+ if (typeof value === 'object') {
+ return {
+ text: value.text || value.nombre || value.name || '',
+ arasaacId: value.arasaacId || value.id || '',
+ };
+ }
+ return { text: String(value), arasaacId: '' };
+}
+
+function TS_buildArasaacPictogramUrl(id) {
+ return `https://static.arasaac.org/pictograms/${id}/${id}_300.png`;
+}
+
+function TS_renderPictoPreview(previewEl, value) {
+ const target = typeof previewEl === 'string' ? document.getElementById(previewEl) : previewEl;
+ if (!target) return;
+ target.innerHTML = '';
+ if (!value.text && !value.arasaacId) {
+ const placeholder = document.createElement('b');
+ placeholder.textContent = 'Seleccionar Pictograma';
+ target.appendChild(placeholder);
+ }
+
+ if (value.arasaacId) {
+ const img = document.createElement('img');
+ img.src = TS_buildArasaacPictogramUrl(value.arasaacId);
+ img.alt = value.text || 'Pictograma';
+ img.width = 100;
+ img.height = 100;
+ img.loading = 'lazy';
+ img.style.objectFit = 'contain';
+ target.appendChild(img);
+ }
+ if (value.text) {
+ const text = document.createElement('span');
+ text.textContent = value.text;
+ target.appendChild(text);
+ }
+}
+
+function TS_applyPictoValue(pictoEl, value) {
+ if (typeof pictoEl === 'string') {
+ pictoEl = document.getElementById(pictoEl);
+ }
+ const plate = TS_normalizePictoValue(value);
+ pictoEl.dataset.PictoValue = JSON.stringify(plate);
+ TS_renderPictoPreview(pictoEl, plate);
+}
+
+function TS_getPictoValue(pictoEl) {
+ if (typeof pictoEl === 'string') {
+ pictoEl = document.getElementById(pictoEl);
+ }
+ if (!pictoEl) return { text: '', arasaacId: '' };
+ const plate = pictoEl.dataset.PictoValue ? JSON.parse(pictoEl.dataset.PictoValue) : { text: '', arasaacId: '' };
+ return TS_normalizePictoValue(plate);
+}
+
+function TS_CreateArasaacSelector(options) {
+ let panelEl = options.panelEl;
+ let searchEl = options.searchEl;
+ let resultsEl = options.resultsEl;
+ let statusEl = options.statusEl;
+ let closeEl = options.closeEl;
+ const debounceId = options.debounceId || safeuuid();
+ const onPick = typeof options.onPick === 'function' ? options.onPick : () => {};
+ let activeContext = null;
+ let overlayEl = null;
+
+ if (options.modal === true && !panelEl) {
+ const overlayId = safeuuid();
+ const panelId = safeuuid();
+ const searchId = safeuuid();
+ const closeId = safeuuid();
+ const statusId = safeuuid();
+ const resultsId = safeuuid();
+
+ overlayEl = document.createElement('div');
+ overlayEl.id = overlayId;
+ overlayEl.style.display = 'none';
+ overlayEl.style.position = 'fixed';
+ overlayEl.style.inset = '0';
+ overlayEl.style.background = 'rgba(0, 0, 0, 0.5)';
+ overlayEl.style.zIndex = '10000';
+ overlayEl.style.alignItems = 'center';
+ overlayEl.style.justifyContent = 'center';
+ overlayEl.style.padding = '16px';
+ overlayEl.innerHTML = html`
+
+ `;
+
+ document.body.appendChild(overlayEl);
+ panelEl = overlayEl.querySelector('#' + panelId);
+ searchEl = overlayEl.querySelector('#' + searchId);
+ resultsEl = overlayEl.querySelector('#' + resultsId);
+ statusEl = overlayEl.querySelector('#' + statusId);
+ closeEl = overlayEl.querySelector('#' + closeId);
+
+ overlayEl.addEventListener('click', (event) => {
+ if (event.target === overlayEl) {
+ close();
+ }
+ });
+ }
+
+ function open(context) {
+ activeContext = context || activeContext;
+ if (overlayEl) {
+ overlayEl.style.display = 'flex';
+ } else if (panelEl) {
+ panelEl.style.display = 'block';
+ }
+ if (searchEl) searchEl.focus();
+ }
+
+ function close() {
+ if (overlayEl) {
+ overlayEl.style.display = 'none';
+ } else if (panelEl) {
+ panelEl.style.display = 'none';
+ }
+ }
+
+ function renderResults(items, term) {
+ if (!resultsEl || !statusEl) return;
+ resultsEl.innerHTML = '';
+ if (!items.length) {
+ statusEl.textContent = `No se encontraron pictogramas para "${term}"`;
+ return;
+ }
+ statusEl.textContent = `${items.length} pictogramas`;
+ items.slice(0, 60).forEach((item) => {
+ const btn = document.createElement('button');
+ btn.type = 'button';
+ btn.style.display = 'flex';
+ btn.style.flexDirection = 'column';
+ btn.style.alignItems = 'center';
+ btn.style.gap = '4px';
+ btn.style.padding = '4px';
+ btn.style.border = '1px solid #ddd';
+ btn.style.background = 'white';
+ btn.style.cursor = 'pointer';
+
+ const img = document.createElement('img');
+ img.src = TS_buildArasaacPictogramUrl(item.id);
+ img.alt = item.label;
+ img.width = 64;
+ img.height = 64;
+ img.loading = 'lazy';
+ img.style.objectFit = 'contain';
+
+ const label = document.createElement('span');
+ label.style.fontSize = '12px';
+ label.textContent = item.label;
+
+ btn.appendChild(img);
+ btn.appendChild(label);
+ btn.onclick = () => {
+ if (!activeContext) return;
+ onPick(activeContext, item);
+ close();
+ };
+ resultsEl.appendChild(btn);
+ });
+ }
+
+ function search(term) {
+ if (!statusEl || !resultsEl) return;
+ const trimmed = term.trim();
+ if (trimmed.length < 2) {
+ statusEl.textContent = 'Escribe al menos 2 caracteres para buscar.';
+ resultsEl.innerHTML = '';
+ return;
+ }
+ statusEl.textContent = 'Buscando...';
+ fetch(`https://api.arasaac.org/api/pictograms/es/search/${encodeURIComponent(trimmed)}`)
+ .then((res) => res.json())
+ .then((items) => {
+ const pictograms = (Array.isArray(items) ? items : [])
+ .map((item) => {
+ if (typeof item === 'string' || typeof item === 'number') {
+ return { id: item, label: trimmed };
+ }
+ const id = item._id || item.id;
+ const keywords = Array.isArray(item.keywords) ? item.keywords : [];
+ const keyword = keywords[0] ? keywords[0].keyword || keywords[0].name : '';
+ const label = keyword || item.keyword || item.name || trimmed;
+ return { id, label };
+ })
+ .filter((item) => item.id);
+ renderResults(pictograms, trimmed);
+ })
+ .catch(() => {
+ statusEl.textContent = 'Error al buscar pictogramas.';
+ resultsEl.innerHTML = '';
+ });
+ }
+
+ if (closeEl) {
+ closeEl.onclick = close;
+ }
+ if (searchEl) {
+ searchEl.addEventListener('input', () =>
+ debounce(debounceId, search, 300, [searchEl.value])
+ );
+ }
+
+ return {
+ open,
+ close,
+ };
+}
+
const wheelcolors = [
// Your original custom colors
'#ff0000',
@@ -922,6 +1284,11 @@ function TS_IndexElement(
if (formattedDate.includes(searchValue)) return true;
}
break;
+ case 'picto': {
+ const plate = TS_normalizePictoValue(value);
+ if (plate.text && plate.text.toLowerCase().includes(searchValue)) return true;
+ break;
+ }
default:
// For raw and other types, search in the direct value
if (String(value).toLowerCase().includes(searchValue)) return true;
@@ -1037,6 +1404,33 @@ function TS_IndexElement(
new_tr.appendChild(tdFechaISO);
break;
}
+ case 'picto': {
+ const tdPicto = document.createElement('td');
+ const plate = TS_normalizePictoValue(data[key.key]);
+ const wrapper = document.createElement('div');
+ wrapper.style.display = 'flex';
+ wrapper.style.alignItems = 'center';
+ wrapper.style.gap = '8px';
+ if (plate.arasaacId) {
+ const img = document.createElement('img');
+ img.src = TS_buildArasaacPictogramUrl(plate.arasaacId);
+ img.alt = plate.text || 'Pictograma';
+ img.width = 48;
+ img.height = 48;
+ img.loading = 'lazy';
+ img.style.objectFit = 'contain';
+ wrapper.appendChild(img);
+ }
+ if (plate.text) {
+ const text = document.createElement('span');
+ console.log('Picto data', data, 'normalized', plate);
+ text.textContent = data[key.labelkey] || plate.text || '';
+ wrapper.appendChild(text);
+ }
+ tdPicto.appendChild(wrapper);
+ new_tr.appendChild(tdPicto);
+ break;
+ }
case 'template': {
const tdCustomTemplate = document.createElement('td');
new_tr.appendChild(tdCustomTemplate);
diff --git a/src/page/comedor.js b/src/page/comedor.js
index 59e2fc6..a23e145 100644
--- a/src/page/comedor.js
+++ b/src/page/comedor.js
@@ -12,7 +12,14 @@ PAGES.comedor = {
}
var nameh1 = safeuuid();
var field_fecha = safeuuid();
- var field_platos = safeuuid();
+ var field_tipo = safeuuid();
+ var field_primero = safeuuid();
+ var field_segundo = safeuuid();
+ var field_postre = safeuuid();
+ var btn_picto_primero = safeuuid();
+ var btn_picto_segundo = safeuuid();
+ var btn_picto_postre = safeuuid();
+ var debounce_picto = safeuuid();
var btn_guardar = safeuuid();
var btn_borrar = safeuuid();
container.innerHTML = html`
@@ -24,18 +31,55 @@ PAGES.comedor = {
+
+
+
`;
+ const pictogramSelector = TS_CreateArasaacSelector({
+ modal: true,
+ debounceId: debounce_picto,
+ onPick: (context, item) => {
+ TS_applyPictoValue(context.pictoId, {
+ text: item.label,
+ arasaacId: String(item.id),
+ });
+ },
+ });
+ document.getElementById(btn_picto_primero).onclick = () =>
+ pictogramSelector.open({ pictoId: btn_picto_primero });
+ document.getElementById(btn_picto_segundo).onclick = () =>
+ pictogramSelector.open({ pictoId: btn_picto_segundo });
+ document.getElementById(btn_picto_postre).onclick = () =>
+ pictogramSelector.open({ pictoId: btn_picto_postre });
DB.get('comedor', mid).then((data) => {
function load_data(data, ENC = '') {
document.getElementById(nameh1).innerText = mid;
document.getElementById(field_fecha).value = data['Fecha'] || mid || CurrentISODate();
- document.getElementById(field_platos).value = data['Platos'] || '';
+ document.getElementById(field_tipo).value = data['Tipo'] || '';
+ document.getElementById(field_primero).value = data['Primero'] || '';
+ document.getElementById(field_segundo).value = data['Segundo'] || '';
+ document.getElementById(field_postre).value = data['Postre'] || '';
+ TS_applyPictoValue(btn_picto_primero, data['Primero_Picto'] || '');
+ TS_applyPictoValue(btn_picto_segundo, data['Segundo_Picto'] || '');
+ TS_applyPictoValue(btn_picto_postre, data['Postre_Picto'] || '');
}
if (typeof data == 'string') {
TS_decrypt(
@@ -60,18 +104,25 @@ PAGES.comedor = {
guardarBtn.style.opacity = '0.5';
const newDate = document.getElementById(field_fecha).value;
+ const newTipo = document.getElementById(field_tipo).value.trim();
var data = {
Fecha: newDate,
- Platos: document.getElementById(field_platos).value,
+ Tipo: newTipo,
+ Primero: document.getElementById(field_primero).value.trim(),
+ Segundo: document.getElementById(field_segundo).value.trim(),
+ Postre: document.getElementById(field_postre).value.trim(),
+ Primero_Picto: TS_getPictoValue(btn_picto_primero),
+ Segundo_Picto: TS_getPictoValue(btn_picto_segundo),
+ Postre_Picto: TS_getPictoValue(btn_picto_postre),
};
// If the date has changed, we need to delete the old entry
- if (mid !== newDate && mid !== '') {
+ if (mid !== newDate + "," + newTipo && mid !== '') {
DB.del('comedor', mid);
}
document.getElementById('actionStatus').style.display = 'block';
- DB.put('comedor', newDate, data)
+ DB.put('comedor', newDate + "," + newTipo, data)
.then(() => {
toastr.success('Guardado!');
setTimeout(() => {
@@ -120,10 +171,31 @@ PAGES.comedor = {
label: 'Fecha',
},
{
- key: 'Platos',
+ key: 'Tipo',
type: 'raw',
default: '',
- label: 'Platos',
+ label: 'Tipo',
+ },
+ {
+ key: 'Primero_Picto',
+ type: 'picto',
+ default: '',
+ label: 'Primero',
+ labelkey: 'Primero',
+ },
+ {
+ key: 'Segundo_Picto',
+ type: 'picto',
+ default: '',
+ label: 'Segundo',
+ labelkey: 'Segundo',
+ },
+ {
+ key: 'Postre_Picto',
+ type: 'picto',
+ default: '',
+ label: 'Postre',
+ labelkey: 'Postre',
},
],
'comedor',