doc/Developer-Guide.md
# Developer Guide
This is a *work in progress*.
It is **far from complete**, content is added as needed.
## Data Modell
### (Individual) Contexts
* All metadata in MAdeK is contained in "contexts"
* Some are built-in ("Core", etc), some are defined by (admin) user
* Contexts that are user-defined are called **"Individual Contexts"**
* In the UI, they are always called "Vocabulary" (in German "Vokabular")!
* **"Individual Contexts"** form a **Vocabulary**, consisting of **Keys** (i.e. "color") and **Terms** (i.e. "green")
#### Assignment
* **"Individual Contexts" (IC)** can be ***assigned to*** and ***activated on*** (Media-)`Sets`
* The assignment is inherited to it's Children `Set`s, from the *inital `Set`* down
* An assigned `Set` can be *activated* and *deactivated* for these child Sets (by User)
#### Implementaion
aka "tricky consequences of this system that we have to take care of"
* When an IC is assigned to a `Set`, it should be *activated* for all the Children!
* ??? — When a `Set` is no longer Child of an *initial Set*, it should retain the IC (by assigning it directly)
#### Queries
(These exist all over the place right now, cleaning that up is TBD)
* `media_set.contexts`: List of all ICs *assigned* to the `Set`
* `context.inherited`: True if the `Set` has inherited the IC (it is not the *initial Set*)
* `context.active`: True if the IC is *activated* for the `Set` (can only be true and is only relevant if `inherited` is also true)
* `context.media_entries`: all `MediaResources` which are contained in a Set (or it's children) for which the IC is *active*
* `.count`: count of these `Resources`
* `context.vocabulary`: List of the `key`s in a context, containg each a list of `term`s
* `key.alphabetical_order`: True if the `term`s in this `key` are sorted alphabetically (as opposed to manually)
* `term.usage_count`: how many of the `context.media_entries` are using this term?
* `.totalcount`: Highest `term.usage_count` for this `context`
## Media Files
### Images
We currently have the following image sizes (aka thumbails):
| Name | Size (longest Side) |
|-------------|----------------------|
| `small` | 100 |
| `small_125` | 125 |
| `medium` | 300 |
| `large` | 500 |
| `x_large` | 768 |
| `maximum` | (original) |
## Routes
- Generate a condensed routing table with following command:
DOC='doc/Routes.md' && echo '|Name|Method|Route|Controller|' > $DOC && echo '|---|---|---|---|' >> $DOC && rake routes | tail -n +2 | grep 'GET' | grep -v 'app_admin' | sed -E 's/[ ]+/|/g' | sed -E 's/$/ |/' | sed -E 's/^\|GET/| |GET/' >> $DOC
## Rails
### Error Handling
TODO: module
If something goes wrong in a controller (or view?),
we `raise` the appropriate error class.
All error classes are defined in `ApplicationController`.
For convenience, the classes and their names are
based on HTTP error codes (4xx/5xx).
Look there for the complete list with some explanations.
### Hooks
TODO: @DrTom (just a very general guideline)
- when to use hooks, when not to
- more importantly: what to never do in certain hooks!
- point to good examples in repo
## Frontend
### `jQuery.fixed-table-headers`
- it is a [magic plugin](http://fixedheadertable.com) that takes care of fixed
headers on tables
- it only works correctly if the table is actually visible
- our js never inits a (somehow) hidden table, so:
- if we ever `.show()` the table (or parent),
**we need to initialize it ourselves!**
- reason: `jQuery` does not have an `.on('show')` event we could hook into
- for convienice, the correct function call is attached to the DOM element,
use it like this:
````js
// find the table
var thetable = $('.laterTableInit');
// call attached function with el as arg
thetable.get(0)._initTable(thetable);
````
### PDF Display
There are two ways PDFs are shown inside madek's HTML:
1. Converted to and embedded as JPG file ("preview", "thumbnail")
2. Embedded as PDF, displayed using `pdf.js` ("document")
Note that there are the usual (per-Entry) **Permissions** at play here,
but they might be confusing:
A User with the *"view"* Permission can only see the
JPG version. **To display the PDF itself the *"download original"* Permission is
needed!**
### `pdf.js`
To display PDFs, [Mozilla's `pdf.js` library](https://mozilla.github.io/pdf.js/)
is used.
There are two places in the UI where PDFs are embedded, with some notable
differences.
- `MediaEntry#show` - `pdf.js/view` is embedded just as an image would be
* no visible UI from `pdf.js`
* custom control elements: page nav, "zoom" (opens `#document`)
- `MediaEntry#document` - only the `pdf.js/view` is loaded
* full pdf.js "Viewer" including UI (toolbars, etc.)
In both cases, an `access_hash` is added to the query in order to provide
authenticated access to the raw file.
#### Upgrading
- currently used version is years behind
- mayor improvements since then (performance, stability)
- also mayor API changes
- might be faster to almost start from scratch
##### Recommended Workflow:
- read the [overview](https://mozilla.github.io/pdf.js/getting_started/)
- get the `#document` to work
- read [API docs and or source](https://mozilla.github.io/pdf.js/api/)
- port over custom controls in `#show`
##### Hints
- the architecture of the library has changed, as laid out in their overview
- for `#show`, embed the `Display` and use it's API.
- for `#document`, embed the complete `Viewer`
- this is mostly abstracted away anyhow in the existing js/coffee,
so the views shouldn't change to much.
- When including `js` and `css`, use the (new) pre-built versions.
This affects (at least) the following sources:
- `app/assets/javascripts/pdf.js.erb`
- `app/assets/stylesheets/pdf-viewer.sass`
- `app/views/media_entries/document.html.haml`
- `app/views/media_entries/previews/document/_full_document.html.haml`
#### etc
- `#show`: better UX before pdf has loaded
- grey background, display `.ui-preloader`
- if pdf height/width-ratio is known, apply it to the preview area