alap - Menus For Links
Tags: link, javascript, json, choice
Published: 2021-05-14 22:52:02

## Overview

Since the dawn of the web, an HTML link is known to lead to one target. I've always thought (since the early 90's) that was somewhat limiting. What if we could provide more choice?

Alap is a JavaScript package that provides a flexible way to attach menus to links. A JSON object defines an id for each possible link target. Within your HTML, anchors refer to one or more ids.  Alap does the work of building up a menus.

Github: [DanielSmith/alap](https://github.com/DanielSmith/alap)

Here is a quick idea of the result:

![CleanShot 2021-05-06 at 20 09 10](https://user-images.githubusercontent.com/167197/117586409-fd622880-b0e5-11eb-836b-65f0fcc375b3.gif)

### Big Picture of what is possible...

* link labels and targets are not hardwired in HTML
* menus are dynamically generated from matched ids and tags
* custom css can be applied on a per-menu, and, per-item basis
* simple expressions: can combine ids and tags with AND, OR, and WITHOUT operations
* menus dismiss themselves with a timeout, or you can click outside them (or hit escape)


### Simple Example

The simplest example is for an HTML anchor to refer to a couple of list element ids.

On the HTML side, that looks like:

```html
I like <a id="cars1" class="alap"
  data-alap-linkitems="bmwe36, vwbug">cars</a>,
```
Alap refers to an object (presumably created from a JSON object from some server call), to find the matches:

```javascript
bmwe36: {
  label: "BMW (E36) - Wikipedia",
  url: "http://en.wikipedia.org/wiki/BMW_3_Series_(E36)",
  tags: ["e36m3", "bmw", "car", "germany"],
},
vwbug: {
  label: "VW Bug",
  url: "http://en.wikipedia.org/wiki/Volkswagen_Beetle",
  tags: ["vw", "car", "germany"],
}
```
When we click on "cars", we get a simple menu:

![image](https://user-images.githubusercontent.com/167197/118197693-6e267f00-b41d-11eb-9d1c-64e04b512eef.png)


So far, we've mentioned two types of IDs:

* the HTML DOM ID (such as "cars1")
* the property IDs in a JavaScript object (such as "bmwe36" and "vwbug")

I think of the JavaScript side as "list item IDs"

_We could just stop there and have enough to use on a page. Alap is something that potentially transforms writing style - you can write something brisk such as "I can't wait to travel to my favorite cities", and have a menu of 10 cities. You don't have to spell out every last detail in main text._

### Using Tags

You probably noticed the `tags` field in a list item object definition:

```javascript
vwbug: {
  label: "VW Bug",
  url: "http://en.wikipedia.org/wiki/Volkswagen_Beetle",
  tags: ["vw", "car", "germany"],
}
```
How are these used?

Let's say we are interested in all of the links we have for a few cities: Sydney, NYC, and London:

```html
<a id="nycsydlon" class="alap"
          data-alap-linkitems=".sydney, .nyc, .london">Sydney, NYC, and London</a>. 
```

This can be thought of much like CSS Classes: We want to match list items that have a tag of "sydney", "nyc", or "london". Here is very edited chunk of list items that would match:

```javascript
    brooklynbridge: {
      label: "Brooklyn Bridge",
      url: "http://en.wikipedia.org/wiki/Brooklyn_Bridge",
      tags: ["nyc", "bridge", "brooklyn", "manhattan"],
    },

    manhattanbridge: {
      label: "Manhattan Bridge",
      url: "http://en.wikipedia.org/wiki/Manhattan_Bridge",
      tags: ["nyc", "bridge", "manhattan"],
    },

    sydneyoz: {
      label: "Sydney, Australia",
      url: "http://en.wikipedia.org/wiki/Sydney",
      tags: ["australia", "sydney", "city"],
    },

    sydneybridgeclimb: {
      label: "Sydney Harbour Bridge Tour",
      url: "http://www.bridgeclimb.com",
      tags: ["australia", "sydney", "tour"],
    },

    sydneybotanical: {
      label: "Sydney Botanical Gardens",
      url: "http://www.rbgsyd.nsw.gov.au/",
      tags: ["australia", "sydney", "park"],
    },

    londontowerbridge: {
      label: "London - Tower Bridge",
      url: "http://en.wikipedia.org/wiki/Tower_Bridge",
      tags: ["london", "city", "bridge"],
    },

    londonhyde: {
      label: "London - Hyde Park",
      url: "http://www.royalparks.gov.uk/Hyde-Park.aspx",
      tags: ["london", "city", "park"],
    },
```

From that, we might get a menu such as:

![image](https://user-images.githubusercontent.com/167197/118317344-efd1e780-b4c5-11eb-9a34-e1de032d4bd5.png)

### Custom CSS

There are two CSS areas that are easy to customize with alap:

* the menu itself
* an individual list item

### the alapelem div

The container for the alap menu is a div with the id of `alapelem`

It also sets a class named `alapelem`

It also picks up a class that is named from the anchor that was clicked.  Example:

```html
<!-- here is our anchor -->
<a id="cars1" class="alap" data-alap-linkitems="bmwe36, vwbug">cars</a>

<!-- the anchor id of "cars1" gives us a class of "alap_cars1" -->
<div id="alapelem" class="alapelem alap_cars1"><ul>
```

This means that in our CSS Styles, we could do something special for a specific menu:

```css
.alap_cars1 {
  /* change the font, colors, etc... */
}
```

### Per-Item override

We can also target CSS for an individual list item.  This is done by using the `cssClass` property in a list item definition:

```javascript
kittyatola_yt: {
  label: "Kitty - Atola Visuals (YouTube)",
  url: "https://www.youtube.com/c/atolavisuals/videos",
  cssClass: "violetclass",
  tags: [
    "atolavisuals",
    "lapeople",
    "cinematography",
    "video",
    "photography",
    "techreview",
    "youtube",
  ],
},
```

In turn, that particular list item generates an extra class (besides `alapListElem`):

```html
class="alapListElem violetclass"
```

which will match a CSS Style Rule:

```css
.violetclass {
  background-color: violet;
}
```

Giving a result where we can style per-item

![image](https://user-images.githubusercontent.com/167197/118336985-cb373900-b4e0-11eb-8a59-53f8e36ba4b3.png)

### Overall Config File, And Settings

Before diving into settings, let's see the overall structure of the Config file:

* settings
* macros
* allLinks

```javascript
export const alapConfig = {
  settings: {
    listType: "ul",
    menuTimeout: 5000,
  },

  macros: {
    cars1: {
      linkItems: "vwbug, bmwe36",
      config: {
        somekey: "somevalue",
      },
    },
  },

  allLinks: {
    vwbug: {
      label: "VW Bug",
      url: "http://en.wikipedia.org/wiki/Volkswagen_Beetle",
      tags: ["vw", "car", "germany"],
    }
  }
};
```

### Global Settings

As you can see, we have two possible settings at the global level:

* listType - `ol` or `ul` for ordered, or unordered list
* menuTimeout - time in ms, before menu dismisses itself (if you mouse away)

### Macros

Throughout this article, We have been referring to list item definitions within the allLinks object. The other main item in the Config is `macros`.

Here is a sample:

```javascript
cars1: {
  linkItems: "vwbug, bmwe36",
  config: {
    somekey: "somevalue",
  }
}
```

For the moment, the `config` section within a macro is not being used.

A macro is referred to in an anchor definition via the `@` character.  Example:

```html
 <a id="cars1" class="alap" data-alap-linkitems="@cars1">cars</a>
```

What is the benefit of using a macro?

A macro lets you say "in my HTML, don't hardwire specifics about the menu I want.  Go look it in up in the Config.  Grab it from the `linkItems` field there".

As a convenience, if you just specify "@", the macro will get its name from the id of the anchor tag. Example: `id="germanbeer" data-alap-linkitems="@"` would be like specifying the macro as "@germanbeer"


### Simple Expressions

Simple expressions let us do AND, OR, and WITHOUT operations.

| operator | description | example            | meaning |
|----------|-------------|--------------------|---------|
| +        | AND         | .nyc + .bridge     | items tagged with nyc AND bridge |
| &#9168;        | OR          | .nyc &#9168; .bridge     | items tagged with nyc OR bridge |
| -        | WITHOUT     | .nyc - .bridge     | items tagged with nyc, WITHOUT a tag of bridge |


_Note: using `|` for OR is much like a list of comma separated items (nyc, bridge). I include the `|` operator to be more complete in what one would expect from expressions._

Expressions can be built up. You can say something like "Show me the links for all of the bridges you know of, but toss out the ones from NYC and London":

```.bridges - .nyc - .london```

### Summing Up For Now

This gives a brief look at what alap does. It's a means of attaching menus to links. Since we use a JSON object to define our labels, link targets, tags, and more, we gain a lot of runtime flexibility. Anchors become a placeholder that express "this is what I want", and alap builds a menu based on the data available.






Photo by <a href="https://unsplash.com/@mrthetrain?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Joshua Hoehne</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>