Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Builder recipes #21

Open
stephenwf opened this issue Jan 31, 2024 · 0 comments
Open

Builder recipes #21

stephenwf opened this issue Jan 31, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@stephenwf
Copy link
Member

During work on the Manifest Editor, some new patterns for create IIIF were created. Usually focussed on creating IIIF from users input. At the moment it's tied to that UI layer, but I think it could be useful as a standalone piece of iiif builder.

Examples

Here is a minimal definition:

interface CreatePlaintextPayload {
  url: string;
  label?: InternationalString;
}

async function createPlaintext(data: CreatePlaintextPayload, ctx: CreatorFunctionContext) {
  return ctx.embed({
    id: data.url,
    type: "Text",
    label: data.label,
    format: "text/plain",
  });
}

export const plaintextCreator: CreatorDefinition = {
  id: "@manifest-editor/plaintext-creator",
  create: createPlaintext,
  label: "Plaintext",
  summary: "Add link to an plaintext",
  resourceType: "ContentResource",
  resourceFields: ["label", "format"],
  supports: {
    parentFields: ["seeAlso", "rendering", "homepage"],
  },
  staticFields: {
    format: "text/plain",
  },
};

It fully describes taking user input:

{
  "id": "https://example.org/some-link",
  "label": { "en": ["Some link"] }
}

And producing:

{
  "id": "https://example.org/some-link",
  "type": "Text",
  "label": { "en": ["Some link"] },
  "format": "text/plain"
}

This example is not a groundbreaking abstraction. But it does allow for more information to be attached. For example, human readable label/summary for what will be created, where this resource is valid from a IIIF point of view, which fields are created - and which are static.

Nesting definitions

Having a "Library" of these definitions allows the Manifest Editor to compose them together.

interface Payload {
  label?: InternationalString;
  body: InternationalString;
  motivation?: string;
  height?: number;
  width?: number;
}

async function createHtmlAnnotation(data: Payload, ctx: CreatorFunctionContext) {
  const annotation = {
    id: ctx.generateId("annotation"),
    type: "Annotation",
  };

  const targetType = ctx.options.targetType as "Annotation" | "Canvas";

  const languages = Object.keys(data.body);
  const bodies = [];
  for (const language of languages) {
    const body = (data.body as any)[language].join("\n");
    if (body) {
      bodies.push(
        await ctx.create(
          "@manifest-editor/html-body-creator",
          {
            language,
            body,
          },
          { parent: { resource: annotation, property: "items" } }
        )
      );
    }
  }

  if (targetType === "Annotation") {
    return ctx.embed({
      ...annotation,
      motivation: data.motivation || ctx.options.initialData?.motivation || "painting",
      body: bodies,
      target: ctx.getTarget(),
    });
  }

  if (targetType === "Canvas") {
    const canvasId = ctx.generateId("canvas");
    const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });

    const annotationResource = ctx.embed({
      ...annotation,
      motivation: "painting",
      body: bodies,
      target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } },
    });

    const page = ctx.embed({
      id: pageId,
      type: "AnnotationPage",
      items: [annotationResource],
    });

    return ctx.embed({
      id: canvasId,
      type: "Canvas",
      label: data.label || { en: ["Untitled HTML canvas"] },
      height: data.height || 1000,
      width: data.width || 1000,
      items: [page],
    });
  }
}

There is a lot going on in this one, but if you look at the definition you can see what it supports:

export const htmlAnnotation: CreatorDefinition = {
  id: "@manifest-editor/html-annotation",
  create: createHtmlAnnotation,
  label: "HTML Annotation",
  summary: "Add HTML annotation",
  resourceType: "Annotation",
  resourceFields: ["id", "type", "motivation", "body", "target"],
  additionalTypes: ["Canvas"],
  supports: {
    initialData: true,
    parentTypes: ["AnnotationPage", "Manifest"],
    parentFields: ["items"],
  },
  staticFields: {
    type: "Annotation",
  },
};

So this produces an Annotation and can be created on:

  • AnnotationPage - Annotation added directly to the page
  • Manifest - A new canvas is created, and the annotation added

In the creator example, there is a "nested" example, which is calling out to another definition:

await ctx.create(
  "@manifest-editor/html-body-creator",
  {
    language,
    body,
  },
  { parent: { resource: annotation, property: "items" } }
);

So you can compose them together.

With IIIF Builder, you could install or create "plugins" and use them to build IIIF either statically, or incrementally in a UI, similar to the Manifest Editor.

@stephenwf stephenwf added the enhancement New feature or request label Jan 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant