# Getting Started
## Prerequisites
You need the [application-prototype](https://labs.sgapps.io/open-source/application-prototype) framework served next to your site -- its two script tags and its `constructors/` folder (the built-in modules the modules of this repository depend on: `extensions/prototype`, `uri-load`, `request`, `custom-elements`, `async`).
```html
```
The modules are plain ES5 files with no build step; they are fetched by the framework's module loader over HTTP, so the repository must be reachable from the page (a static server, not `file://`).
## Installation
Clone the repository next to your site. The modules live directly at the repository root (there is no `modules/` folder):
```
my-site/
application-prototype/ <-- the framework (ApplicationPrototype.js, ApplicationBuilder.js, constructors/)
application-prototype-modules/ <-- this repository
lib.js <-- registers the 10 module names
custom-elements/ lib.js, scroller.js + scroller/style.css
elements/ popup.js, notify.js, notify-service.js, context-menu.js, crop-sections.js, tree-node.js (+ one folder each)
gadgets/ wrapper.js, grid-panel.js + grid-panel/{block,grid}.js
application-patterns/ routing.js + routing/{components,resources,routes}.js
docs/ this documentation and the playground
```
```sh
git clone git@labs.sgapps.io:open-source/application-prototype-modules.git
```
No `npm install` is needed to use the modules. `npm start` serves the landing page, the documentation and the playground locally (see [Development](#development)).
## Registering All Modules
`lib.js` registers every module path with the framework. Require it by **root-relative path or absolute URL** (module names are resolved relative to the folder `lib.js` was loaded from) and call the exported function once during startup:
```js
var App = new ApplicationBuilder({
onready: function () {
var App = this;
App.modulePath('/application-prototype/constructors');
App.require(['extensions/prototype', 'lib'], function (libs) {
// register the framework's built-in modules by name
libs.lib();
// register the modules of this repository by name
App.require('/application-prototype-modules/lib.js').then(function (loader) {
loader();
console.log('modules registered');
});
});
}
});
```
`loader()` runs `Application.moduleRegister(__dirname, [...])` for the list below; after that every module is available through `Application.require()` (or `App.require()`) by its short name:
| Name | File |
|---|---|
| `custom-elements/lib` | `custom-elements/lib.js` |
| `custom-elements/scroller` | `custom-elements/scroller.js` |
| `elements/context-menu` | `elements/context-menu.js` |
| `elements/crop-sections` | `elements/crop-sections.js` |
| `elements/tree-node` | `elements/tree-node.js` |
| `elements/popup` | `elements/popup.js` |
| `elements/notify` | `elements/notify.js` |
| `elements/notify-service` | `elements/notify-service.js` |
| `gadgets/wrapper` | `gadgets/wrapper.js` |
| `gadgets/grid-panel` | `gadgets/grid-panel.js` |
The playground pages register the same way: `App.moduleRegister('/vendor/modules', ['lib#?module=libModules'])` (`/vendor/modules` is a placeholder the playground resolves to the repository root or to the CDN copy) gives the file a name, `App.require('libModules')` loads it, `lib.libModules()` registers the list.
## Loading a Module
### Single module
```js
Application.require('elements/notify').then(function (NotifyManager) {
var notify = NotifyManager();
document.body.appendChild(notify.node());
notify.info('Hello', 'The notification manager is ready');
});
```
### Multiple modules with aliases
```js
Application.require([
"popup :: elements/popup",
"menu :: elements/context-menu",
"panels :: elements/crop-sections"
]).then(function (libs) {
libs.popup.alert('Title', 'Text');
var menu = libs.menu();
var panels = libs.panels();
});
```
## How Modules Work
### Factories that return an `ApplicationPrototype`
`elements/context-menu`, `elements/crop-sections`, `elements/tree-node`, `elements/notify`, `elements/notify-service`, `gadgets/wrapper` and `gadgets/grid-panel` export a **factory**: calling it builds one instance -- an `ApplicationPrototype` with methods attached through `.bind()`:
```js
var app = new ApplicationPrototype();
app.bind("node", function () { return config.node; });
app.bind("show", function (pos) { /* ... */ return app; });
module.exports = function () { /* ... */ return app; };
```
Every bound method is observable: `instance.on('beforeShow', fn)` runs before the call (return `false` to veto), `'onShow'` with it and `'afterShow'` on the next tick. Methods bound with an empty configuration string (`app.bind("node", fn, "")`) are plain functions without hooks -- the module pages say which.
### Static objects
`elements/popup` exports a plain object of functions (`popup`, `alert`, `prompt`, `confirm`); `custom-elements/lib` exports one function; `custom-elements/scroller` exports `true` once the tag is registered; `application-patterns/routing` exports `{ components, resources }`.
### Stylesheets and templates
A module that needs CSS links its own stylesheet when it loads, through the framework's `uri-load` and `module.resourceUrl('style.css')` (the URL is relative to the module file, so the folder structure must stay as it is). `elements/crop-sections` also fetches its two HTML templates with `request`. Nothing is inlined into your page and nothing is loaded from a CDN.
The dialogs (`elements/popup`), the notifications (`elements/notify`) and the context menu (`elements/context-menu`) are designed for the SGApps **RegalRoyal** theme and use its class names (`rr-button`, `rr-button-danger`, `rr-block-space`, `rr-menu rr-menu-vertical`, `regal-royal--dark-theme`, the `websymbols` icon font, the `animated` / `bounceIn` / `fadeIn` animation classes). With the theme on the page they take its look; without it they render with the browser's defaults and the module's own `style.css` (positioning, overlay, colours of the notification types). The theme is available at `https://sgapps.io/addons/RegalRoyal/styles/less/style.less.cache.css` -- the playground examples of those three modules link it.
### Custom elements
`` is not a `customElements.define()` element. `custom-elements/lib` hands the tag -> module map to the framework's `custom-elements` module (`lazyLoadModules`), which watches `document.body` with a `MutationObserver` and requires `custom-elements/scroller` the first time the tag is seen; the scroller module then calls `registerMethods('sgapps-scroller', { __onInit, ... })` and every element gets its `attrdata.SGAppsScroller` API. Options are declared with `attrb-*` attributes (JSON-parsed by `extensions/prototype`'s `attrdata`).
## Development
```sh
npm start # landing page + docs + playground at http://localhost:3000/ and /docs/
npm run docs-site-published # serves docs/ alone, the layout of a published docs-only site
npm test # lints the documentation: links, sidebar, playground registry, landing page, lib.js coverage
```
The playground (`docs/playground.html`) loads the framework from the SGApps CDN (`https://cdn.sgapps.io/components/application-prototype`, 1.31.0, CORS enabled) and the modules from the repository root (one level above `docs/`) when it is served, so every example runs on your working copy; when only `docs/` is served (the published site) it falls back to the CDN copy at `https://cdn.sgapps.io/components/application-prototype-modules`. Append `#lib=` or `#modules=` to the playground URL to run the examples on another checkout (a local framework checkout served by the same server, another version, ...).
## Next Steps
- [Popup](elements/popup.md) -- dialogs: `alert`, `confirm`, `prompt`, custom content
- [Notify](elements/notify.md) and [Notify Service](elements/notify-service.md) -- toast notifications
- [Context Menu](elements/context-menu.md) -- right-click menus with sub-lists
- [Crop Sections](elements/crop-sections.md) -- collapsible side-by-side panels
- [Grid Panel](gadgets/grid-panel.md) -- a dashboard layout editor
- [sgapps-scroller](custom-elements/scroller.md) -- transform-based scrolling
- [Routing](application-patterns/routing.md) -- the static routing pattern