README.md
[![npm version](https://badge.fury.io/js/finderjs.svg)](https://badge.fury.io/js/finderjs)
[![Build Status](https://travis-ci.org/mynameistechno/finderjs.svg?branch=master)](https://travis-ci.org/mynameistechno/finderjs)
[![Code Climate](https://codeclimate.com/github/mynameistechno/finderjs/badges/gpa.svg)](https://codeclimate.com/github/mynameistechno/finderjs)
[![Test Coverage](https://codeclimate.com/github/mynameistechno/finderjs/badges/coverage.svg)](https://codeclimate.com/github/mynameistechno/finderjs/coverage)
# finderjs
Finder-like UI component for viewing hierarchical content in columns.
Demo:
[http://mynameistechno.github.io/finderjs/](http://mynameistechno.github.io/finderjs/)
### React
The engineering team at AndcultureCode has written a React wrapper for finderjs! Check it out:
[https://github.com/AndcultureCode/react-finderjs](https://github.com/AndcultureCode/react-finderjs)
## Installation
```bash
npm install finderjs
```
## Usage
Use it as a CommonJS module, as a standalone script, or as a jQuery plugin. Roll your own CSS or feel free to use the styling in `example/finderjs.css`, which leverages flexbox.
In its simplest form:
```javascript
var f = finder(container, data, options);
```
| Parameter | Type | Description |
| --------------------------- | ------------------- | ----------------------------------------- |
| container | Element | Container element for finder |
| [data](#source-is-an-array) | Array|Function | Data source can be an array or function |
| [options](#options) | Object | Configure classNames, item rendering, etc |
### Data
The hierarchical data is represented with nested arrays. A data source can be an array or a function that executes a callback with the data (an array). This is handy for asynchronous data, such as a remote web service.
#### Source is an array
Each item in the array itself should be an object. When the data source is an array, each object that doesn't contain a `children` property is considered a leaf node. When a leaf node is selected, the `leaf-selected` event will be emitted. When present, the value of the `children` property should be an array. When a node has children and it is selected, it will use the `children` to populate the next column.
```javascript
var container = document.getElementById('container');
var data = [
{
label: 'Item 1',
children: [
{
label: 'Item 1A',
children: [
{
label: 'Item 1A1'
}
]
},
{
label: 'Item 1B'
}
]
}
];
var options = {};
var f = finder(container, data, options);
f.on('leaf-selected', function(item) {
console.log('Leaf selected', item);
});
```
See [this example](example/example-static.js) for more details.
#### Source is a function
When the data source is a function there is no need for the `children` property. This function will be called on every selection and will pass along the selected item. A callback is provided and should be called only if there are children for a new column.
```javascript
var container = document.getElementById('container');
var options = {};
/**
* This function will be called on load and on every selection.
* @param {Object} parent - item that was selected
* @param {Object} cfg - config object
* @param {Function} callback - call this with the data (Array)
*/
function remoteSource(parent, cfg, callback) {
var children = [...];
if (children.length) {
callback(children);
}
}
var f = finder(container, remoteSource, options);
```
See [this example](example/example-async.js) for more details.
#### Notes
If an object has a `url` property it will be treated slightly differently: the anchor tag that wraps the item will have the `href` attribute assigned to it. Upon selection of this item the browser will be redirected to the provided URL.
### Events
`finder` will return an EventEmitter which allows you to listen to (and emit) the following events:
| Event | Description |
| ------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `item-selected` | An item was selected (clicked or keyboard arrow) |
| `leaf-selected` | A leaf node was selected |
| `interior-selected` | An interior node was selected |
| `create-column` | Append a column to the container |
| `column-created` | A column was appended to the container |
| `navigate` | Navigate the finder by going `up`, `down`, `right`, or `left` |
| `go-to` | Specify a path to programmatically "go to". Accepts a string or array, e.g. `path/file.txt` or `['path', 'file.txt']` |
Note that for historical reasons, `leaf-selected` and `interior-selected` receive the node object from the data model, while `item-selected` receives the DOM elements for the column and item selected.
See the examples for more [details](example).
### Options
| Option | Type | Description |
| ------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `className` | Object | Override the [default classnames](https://github.com/mynameistechno/finderjs/blob/master/index.js#L14) by populating this object |
| `labelKey` | string | Override the data key used to render labels. Defaults to `label`. |
| `childKey` | string | Override the data key used to populate children. Defaults to `children`. |
| `createItemContent` | Function | Define how each item is rendered. The first parameter passed in is the `config` object and the second is the `item` object that is currently being iterated on. It should return an HTML Element. |
| `defaultPath` | string or array | Specify path to preselect on load. E.g. `path/file.txt` or `['path', 'file.txt']`. |
## Project commands
| Command | Description |
| --------------------------------- | ----------------------------------------- |
| `npm install` | Install dependencies into `node_modules/` |
| `make build` | Build finderjs and example |
| `make install` | Clears node_modules and installs |
| `make clean` | Remove build and coverage data |
| `make lint` | Lint files |
| `make test` | Run tests |
| `make cover` | Run coverage tests |
| `make watch in=<file> out=<file>` | Watchify a file |