Saltar al contenido principal

Contexto de selección

Cuando un usuario selecciona elementos en Zotero, el plugin construye un Contexto de Selección (SelectionContext) estructurado que describe qué seleccionó el usuario y a qué tipo pertenece cada elemento seleccionado. Este contexto sirve como base de entrada para el Hook buildRequest.

Tipos de selección​

Basándose en la combinación de tipos de elementos seleccionados, selectionContext.selectionType devuelve uno de los siguientes valores:

TipoDescripción
"parent"Todos los elementos seleccionados son elementos padre (elementos de nivel superior)
"child"Todos los elementos seleccionados son elementos hijo (elementos no de nivel superior)
"attachment"Todos los elementos seleccionados son adjuntos
"note"Todos los elementos seleccionados son notas
"mixed"Los elementos seleccionados son una mezcla de múltiples tipos
"none"No hay elementos seleccionados

Estructura del contexto​

selectionContext = {
selectionType: "parent", // Tipo de selección
items: {
parents: [ /* Lista de elementos padre */ ],
children: [ /* Lista de elementos hijo */ ],
attachments: [ /* Lista de adjuntos */ ],
notes: [ /* Lista de notas */ ],
},
summary: {
parentCount: 2,
childCount: 0,
attachmentCount: 0,
noteCount: 0,
},
warnings: [], // Mensajes de advertencia
sampledAt: "2026-01-15T...", // Hora de creación del contexto
}

Cada tipo de elemento contiene rica información contextual.

Elemento padre (ParentContext)​

Un elemento padre es un elemento de nivel superior en la biblioteca de Zotero (p. ej., artículo de revista, libro, página web, etc.). Cada contexto de elemento padre contiene:

{
item: Zotero.Item, // Objeto del elemento
id: number, // ID del elemento
title: string, // Título
attachments: [ // Adjuntos hijo bajo este elemento
{ type, filePath, mimeType, dateAdded, ... }
],
notes: [ // Notas hijo bajo este elemento
{ id, content, ... }
],
tags: string[], // Lista de etiquetas
collections: string[], // Colecciones que lo contienen
children: [ // Otros elementos hijo
{ id, type, ... }
],
}

Adjunto (AttachmentContext)​

Un adjunto es un archivo adjunto de un elemento (PDF, Markdown, etc.). Cada contexto de adjunto contiene:

{
item: Zotero.Item, // Objeto del elemento adjunto
id: number, // ID del elemento
filePath: string, // Ruta local del archivo
fileName: string, // Nombre del archivo
mimeType: string, // Tipo MIME (p. ej., "application/pdf")
dateAdded: Date, // Fecha de adición
parentItem: { // Elemento padre propietario
id: number,
key: string,
libraryID: number,
},
tags: string[],
collections: string[],
}

Nota (NoteContext)​

{
item: Zotero.Item,
id: number,
content: string, // Contenido de la nota (HTML)
parentItem: { id, key, libraryID },
tags: string[],
}

Uso del contexto de selección en Hooks​

Obtener adjuntos seleccionados​

export function buildRequest({ selectionContext, runtime }) {
const attachments = selectionContext.items.attachments;

return {
kind: "skillrunner.job.v1",
create: { skill_id: "my-skill" },
input: {
files: attachments.map((attachment) => ({
path: runtime.helpers.getAttachmentFilePath(attachment),
name: runtime.helpers.getAttachmentFileName(attachment),
})),
},
};
}

Obtener elementos padre seleccionados y su contenido hijo​

export function buildRequest({ selectionContext, runtime }) {
const parents = selectionContext.items.parents;

for (const parent of parents) {
const title = parent.item.getField("title");
const attachments = parent.attachments; // Adjuntos bajo este elemento padre
const notes = parent.notes; // Notas bajo este elemento padre
}

// ...
}

Verificar el tipo de selección para determinar el comportamiento​

export function preflight({ selectionContext }) {
const { selectionType } = selectionContext;

if (selectionType === "none") {
// No hay elementos seleccionados, omitir
return { kind: "skip", reason: "no selected items" };
}

if (selectionType === "attachment") {
// El usuario seleccionó solo adjuntos, usar lógica de procesamiento de adjuntos
} else if (selectionType === "parent") {
// El usuario seleccionó solo elementos padre, expandir el primer adjunto que cumpla los requisitos
}

return { kind: "continue", context: { selectionType } };
}

Attachment Candidate Planning​

{
"inputs": {
"member": {
"kind": "attachment",
"accepts": { "mime": ["application/pdf"] }
},
"grouping": { "mode": "each" }
},
"validateSelection": {
"require": {
"selection": {
"counts": { "attachments": { "min": 1 } },
"allowMixed": false
}
},
"select": { "policy": "input-member", "source": "selected" },
"filters": [
{ "kind": "source-file-exists", "phase": "availability" }
]
}
}

require.selection reads the original SelectionContext once. The selector produces ordered candidates, attachment MIME compatibility runs before filters, and inputs.grouping creates immutable top-level units.

Workflows Without Selected Items​

Use member.kind: "selection", grouping.mode: "all", the selection selector, and trigger.requiresSelection: false. The selector then produces the complete empty SelectionContext as the single member. Selection requirements remain active and must not make the empty selection impossible.

Declarative Candidate Filters​

{
"validateSelection": {
"select": { "policy": "generated-note-candidates" },
"filters": [
{
"kind": "generated-note-kinds-absent",
"phase": "availability",
"noteKinds": ["digest"]
}
]
}
}

validateSelection owns candidate production and filtering. inputs owns the execution member and grouping. Hooks consume the prepared unit and must not reconstruct selection planning.

Próximos pasos​