Repository: rijs/fullstack
Branch: master
Commit: 82f6e5ebe4a5
Files: 15
Total size: 64.6 KB
Directory structure:
gitextract__zv91krg/
├── .gitattributes
├── .gitignore
├── .travis.yml
├── README.md
├── client/
│ ├── ripple.bundle.js
│ └── ripple.js
├── index.js
├── package.json
├── rollup.config.js
├── rollup.pure.config.js
└── tests/
├── basic.test.js
└── resources/
├── _components/
│ ├── x-foo.css
│ └── x-foo.js
├── components/
│ └── auto-loaded-component.js
└── utils/
└── foo.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
dist/* -diff
================================================
FILE: .gitignore
================================================
node_modules
coverage
*.log
================================================
FILE: .travis.yml
================================================
sudo: false
language: node_js
node_js:
- "stable"
after_script: NODE_ENV=test istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage
================================================
FILE: README.md
================================================
# Ripple Fullstack
On the server:
**`index.js`**
```js
const ripple = require('rijs')({ dir: __dirname })
```
On the client:
**`pages/index.html`**
```html
```
Run it:
```
$ node index.js
```
This starts up a server on a random port and statically serves your `/pages` directory. You can also specify a `port` to always use, or pass an existing HTTP `server` (e.g. from express).
Clients will then just be streamed the fine-grained resources they are using (i.e. everything is lazy loaded, no bundling, no over-fetching).
Ripple keeps clients/servers in sync by replicating an immutable log of actions in the background, and subsequently the view - or other modules - which are reactively updated when the local store is updated.
That's it! No boilerplate necessary, no build pipeline, no special transpilation, no magical CLI.
The basic API is:
```js
ripple(name) // getter
ripple(name, body) // setter
ripple.on('change', (name, change) => { .. })
```
## Components
Let's add a (Web) Component to the page:
**`index.html`**
```diff
+
```
Let's define the component:
**`resources/my-app.js:`**
```js
export default () => ()
```
Ripple is agnostic to _how_ you write your components, they should just be idempotent: a single render function.
This is fine:
**`resources/my-app.js:`**
```js
export default (node, data) => node.innerHTML = 'Hello World!'
```
Or using some DOM-diff helper:
**`resources/my-app.js:`**
```js
export default (node, data) => jsx(node)`
Hello World
`
```
Or using [once](https://github.com/utilise/once#once)/D3 joins:
**`resources/my-app.js:`**
```js
export default (node, data) => {
once(node)
('h1', 1)
.text('Hello World')
})
```
For more info about writing idempotent components, see [this spec](https://github.com/pemrouz/vanilla).
## State/Data
The first parameter of the component is the node to update.
The second parameter contains all the state and data the component needs to render:
```js
export default function component(node, data){ ... }
```
* You can inject data resources by adding the name of the resources to the data attribute:
```html
```
```js
export default function shop({ stock }){ ... }
```
Declaring the data needed on a component is used to reactively rerender it when the data changes.
Alternatively, you can use `ripple.pull` directly to retrieve a resource, which has similar semantics to [dynamic `import()`](https://github.com/tc39/proposal-dynamic-import) (i.e. resolves from local cache or returns a single promise):
```js
const dependency = await pull('dependency')
```
* The other option is to explicitly pass down data to the component from the parent:
```js
once(node)
('my-shop', { stock })
```
The helper function will set the state and redraw, so redrawing a parent will redraw it's children. If you want to do it yourself:
```js
element.state = { stock }
element.draw()
```
## Defaults
You can set defaults using the ES6 syntax:
```js
export default function shop({ stock = [] }){ ... }
```
If you need to persist defaults on the component's state object, you can use a small [helper function](https://github.com/utilise/utilise#--defaults):
```js
export default function shop(state){
const stock = defaults(state, 'stock', [])
}
```
## Updates
#### Local state
Whenever you need to update local state, just change the `state` and invoke a redraw (like a game loop):
```js
export default function abacus(node, state){
const o = once(node)
, { counter = 0 } = state
o('span', 1)
.text(counter)
o('button', 1)
.text('increment')
.on('click.increment' d => {
state.counter++
o.draw()
})
}
```
#### Global state
Whenever you need to update global state, you can simply compute the new value and register it again which will trigger an update:
```js
ripple('stock', {
apples: 10
, oranges: 20
, pomegranates: 30
})
```
Or if you just want to change a part of the resource, use a [functional operator](https://github.com/utilise/utilise#--set) to apply a finer-grained diff and trigger an update:
```js
update('pomegranates', 20)(ripple('stock'))
// same as: set({ type: 'update', key: 'pomegranate', value: 20 })(ripple('stock'))
```
Using logs of atomic diffs combines the benefits of immutability with a saner way to synchronise state across a distributed environment.
Components are rAF batched by default. You can access the list of all relevant changes since the last render in your component via `node.changes` to make it more performant if necessary.
## Events
Dispatch an event on the root element to communicate changes to parents (`node.dispatchEvent`).
## Routing
Routing is handled by your top-level component: Simply parse the URL to determine what children to render and invoke a redraw of your application when the route has changed:
```js
export function app(node, data){
const o = once(node)
, { pathname } = location
o('page-dashboard', pathname == '/dashboard')
o('page-login', pathname == '/login')
once(window)
.on('popstate.nav', d => o.draw())
}
```
This solution is not tied to any library, and you may not need one at all.
For advanced uses cases, checkout [decouter](https://github.com/pemrouz/decouter).
## Styling
You can author your stylesheets assuming they are completely isolated, using the Web Component syntax (`:host` etc).
They will either be inserted in the shadow root of the element, or scoped and added to the head if there is no shadow.
By default, the CSS resource `component-name.css` will be automatically applied to the component `component-name`.
But you can apply multiple stylesheets to a component too: just extend the `css` attribute.
## Folder Convention
All files in your `/resources` folder will be automatically registered (except tests etc). You can organise it as you like, but I recommend using the convention: a folder for each component (to co-locate JS, CSS and tests), and a `data` folder for the resources that make up your domain model.
```
resources
├── data
│ ├── stock.js
│ ├── order.js
│ └── ...
├── my-app
│ ├── my-app.js
│ ├── my-app.css
│ └── test.js
├── another-component
│ ├── another-component.js
│ ├── another-component.css
│ └── test.js
└── ...
```
Hot reloading works out of the box. Any changes to these files will be instantly reflected everywhere.
## Loading Resources
You can also get/set resources yourselves imperatively:
```js
ripple(name) // getter
ripple(name, body) // setter
```
Or for example import resources from other packages:
```js
ripple
.resource(require('external-module-1'))
.resource(require('external-module-2'))
.resource(require('external-module-3'))
```
You can also create resources that proxy to [fero](https://github.com/pemrouz/fero)) services too.
## Offline
Resources are currently cached in `localStorage`.
This means even _before_ any network interaction, your application renders the last-known-good-state for a superfast startup.
Then as resources are streamed in, the relevant parts of the application are updated.
Note: Caching of resources will be improved by using ServiceWorkers under the hood instead soon ([#27](https://github.com/rijs/fullstack/issues/27))
## Render Middleware
By default the draw function just invokes the function on an element. You can extend this without any framework hooks using the explicit decorator pattern:
```js
// in component
export default function component(node, data){
middleware(node, data)
}
// around component
export default middleware(function component(node, data){
})
// for all components
ripple.draw = middleware(ripple.draw)
```
A few useful middleware included in this build are:
### Needs
[This middleware](https://github.com/rijs/needs#ripple--needs) reads the `needs` header and applies the attributes onto the element. The component does not render until all dependencies are available. This is useful when a component needs to define its own dependencies. You can also supply a function to dynamically calculate the required resources.
```js
export default {
name: 'my-component'
, body: function(){}
, headers: { needs: '[css=..][data=..]' }
}
```
### Shadow
If supported by the browser, a shadow root will be created for each component. The component will render into the shadow DOM rather than the light DOM.
### Perf (Optional)
This one is not included by default, but you can use this to log out the time each component takes to render.
Other debugging tips:
* Check `ripple.resources` for a snapshot of your application. Resources are in the [tuple format](https://github.com/rijs/core#ripple--core) `{ name, body, headers }`.
* Check `$0.state` on an element to see the state object it was last rendered with or manipulate it.
## Sync
You can define a `from` function in the resource headers which will process requests from the client:
```js
const from = (req, res) =>
req.data.type == 'REGISTER' ? register(req, res)
: req.data.type == 'FORGOT' ? forgot(req, res)
: req.data.type == 'LOGOUT' ? logout(req, res)
: req.data.type == 'RESET' ? reset(req, res)
: req.data.type == 'LOGIN' ? login(req, res)
: false
module.exports = {
name: 'users'
, body: {}
, headers: { from }
}
```
This can return a single value, a promise or a stream. On the client you make requests with `ripple.send(name, type, value)`. This returns an awaitable [stream](https://github.com/utilise/emitterify/#emitterify).
You can also use the `.subscribe` API to subscribe to all or part of a resource. The key can be arbitrarily deep, and multiple keys will be merged into a single object.
```js
ripple.subscribe(name, key)
ripple.subscribe(name, [keys])
```
Subscriptions are automatically deduplicated are ref-counted, so components can indepedently subscribe to the data they need without worrying about this.
Note that you can also use `ripple.get` instead of subscribe if you just want to get a single value and then automatically unsubscribe.
## Ripple Minimal
If you have don't have backend for your frontend, checkout [rijs/minimal](https://github.com/rijs/minimal) which is a client-side only build of Ripple.
You can also adjust your own framework by [adding/removing modules](https://github.com/rijs/minimal/blob/master/src/index.js#L1-L11).
## Docs
See [rijs/docs](https://github.com/rijs/docs) for more guides, index of modules, API reference, etc
================================================
FILE: client/ripple.bundle.js
================================================
var rijs = (function () {
'use strict';
function commonjsRequire () {
throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
}
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var client = typeof window != 'undefined';
var client$1 = /*#__PURE__*/Object.freeze({
default: client,
__moduleExports: client
});
var promise_1 = promise;
function promise() {
var resolve
, reject
, p = new Promise(function(res, rej){
resolve = res, reject = rej;
});
arguments.length && resolve(arguments[0]);
p.resolve = resolve;
p.reject = reject;
return p
}
var promise$1 = /*#__PURE__*/Object.freeze({
default: promise_1,
__moduleExports: promise_1
});
var flatten = function flatten(p,v){
if (v instanceof Array) { v = v.reduce(flatten, []); }
return (p = p || []), p.concat(v)
};
var flatten$1 = /*#__PURE__*/Object.freeze({
default: flatten,
__moduleExports: flatten
});
var has = function has(o, k) {
return k in o
};
var has$1 = /*#__PURE__*/Object.freeze({
default: has,
__moduleExports: has
});
var has$2 = ( has$1 && has ) || has$1;
var def = function def(o, p, v, w){
if (o.host && o.host.nodeName) { o = o.host; }
if (p.name) { v = p, p = p.name; }
!has$2(o, p) && Object.defineProperty(o, p, { value: v, writable: w });
return o[p]
};
var def$1 = /*#__PURE__*/Object.freeze({
default: def,
__moduleExports: def
});
var promise$2 = ( promise$1 && promise_1 ) || promise$1;
var flatten$2 = ( flatten$1 && flatten ) || flatten$1;
var def$2 = ( def$1 && def ) || def$1;
var noop = function(){};
var emitterify = function emitterify(body, hooks) {
body = body || {};
hooks = hooks || {};
def$2(body, 'emit', emit, 1);
def$2(body, 'once', once, 1);
def$2(body, 'off', off, 1);
def$2(body, 'on', on, 1);
body.on['*'] = body.on['*'] || [];
return body
function emit(type, pm, filter) {
var li = body.on[type.split('.')[0]] || []
, results = [];
for (var i = 0; i < li.length; i++)
{ if (!li[i].ns || !filter || filter(li[i].ns))
{ results.push(call(li[i].isOnce ? li.splice(i--, 1)[0] : li[i], pm)); } }
for (var i = 0; i < body.on['*'].length; i++)
{ results.push(call(body.on['*'][i], [type, pm])); }
return results.reduce(flatten$2, [])
}
function call(cb, pm){
return cb.next ? cb.next(pm)
: pm instanceof Array ? cb.apply(body, pm)
: cb.call(body, pm)
}
function on(type, opts, isOnce) {
var id = type.split('.')[0]
, ns = type.split('.')[1]
, li = body.on[id] = body.on[id] || []
, cb = typeof opts == 'function' ? opts : 0;
return !cb && ns ? (cb = body.on[id]['$'+ns]) ? cb : push(observable(body, opts))
: !cb && !ns ? push(observable(body, opts))
: cb && ns ? push((remove(li, body.on[id]['$'+ns] || -1), cb))
: cb && !ns ? push(cb)
: false
function push(cb){
cb.isOnce = isOnce;
cb.type = id;
if (ns) { body.on[id]['$'+(cb.ns = ns)] = cb; }
li.push(cb)
;(hooks.on || noop)(cb);
return cb.next ? cb : body
}
}
function once(type, callback){
return body.on(type, callback, true)
}
function remove(li, cb) {
var i = li.length;
while (~--i)
{ if (cb == li[i] || cb == li[i].fn || !cb)
{ (hooks.off || noop)(li.splice(i, 1)[0]); } }
}
function off(type, cb) {
remove((body.on[type] || []), cb);
if (cb && cb.ns) { delete body.on[type]['$'+cb.ns]; }
return body
}
function observable(parent, opts) {
opts = opts || {};
var o = emitterify(opts.base || promise$2());
o.i = 0;
o.li = [];
o.fn = opts.fn;
o.parent = parent;
o.source = opts.fn ? o.parent.source : o;
o.on('stop', function(reason){
o.type
? o.parent.off(o.type, o)
: o.parent.off(o);
return o.reason = reason
});
o.each = function(fn) {
var n = fn.next ? fn : observable(o, { fn: fn });
o.li.push(n);
return n
};
o.pipe = function(fn) {
return fn(o)
};
o.map = function(fn){
return o.each(function(d, i, n){ return n.next(fn(d, i, n)) })
};
o.filter = function(fn){
return o.each(function(d, i, n){ return fn(d, i, n) && n.next(d) })
};
o.reduce = function(fn, acc) {
return o.each(function(d, i, n){ return n.next(acc = fn(acc, d, i, n)) })
};
o.unpromise = function(){
var n = observable(o, { base: {}, fn: function(d){ return n.next(d) } });
o.li.push(n);
return n
};
o.next = function(value) {
o.resolve && o.resolve(value);
return o.li.length
? o.li.map(function(n){ return n.fn(value, n.i++, n) })
: value
};
o.until = function(stop){
return stop.each ? stop.each(o.stop) // TODO: check clean up on stop too
: stop.then ? stop.then(o.stop)
: stop.call ? o.filter(stop).map(o.stop)
: 0
};
o.off = function(fn){
return remove(o.li, fn), o
};
o.start = function(){
o.source.emit('start');
return o
};
o.stop = function(reason){
return o.source.emit('stop', reason)
};
o[Symbol.asyncIterator] = function(){
return {
next: function(){
return o.wait = new Promise(function(resolve){
o.wait = true;
o.map(function(d, i, n){
delete o.wait;
o.off(n);
resolve({ value: d, done: false });
});
o.emit('pull', o);
})
}
}
};
return o
}
};
var emitterify$1 = /*#__PURE__*/Object.freeze({
default: emitterify,
__moduleExports: emitterify
});
var is_1 = is;
is.fn = isFunction;
is.str = isString;
is.num = isNumber;
is.obj = isObject;
is.lit = isLiteral;
is.bol = isBoolean;
is.truthy = isTruthy;
is.falsy = isFalsy;
is.arr = isArray;
is.null = isNull;
is.def = isDef;
is.in = isIn;
is.promise = isPromise;
is.stream = isStream;
function is(v){
return function(d){
return d == v
}
}
function isFunction(d) {
return typeof d == 'function'
}
function isBoolean(d) {
return typeof d == 'boolean'
}
function isString(d) {
return typeof d == 'string'
}
function isNumber(d) {
return typeof d == 'number'
}
function isObject(d) {
return typeof d == 'object'
}
function isLiteral(d) {
return d.constructor == Object
}
function isTruthy(d) {
return !!d == true
}
function isFalsy(d) {
return !!d == false
}
function isArray(d) {
return d instanceof Array
}
function isNull(d) {
return d === null
}
function isDef(d) {
return typeof d !== 'undefined'
}
function isPromise(d) {
return d instanceof Promise
}
function isStream(d) {
return !!(d && d.next)
}
function isIn(set) {
return function(d){
return !set ? false
: set.indexOf ? ~set.indexOf(d)
: d in set
}
}
var is$1 = /*#__PURE__*/Object.freeze({
default: is_1,
__moduleExports: is_1
});
var client$2 = ( client$1 && client ) || client$1;
var is$2 = ( is$1 && is_1 ) || is$1;
var colorfill_1 = colorfill();
function colorfill(){
/* istanbul ignore next */
['red', 'green', 'bold', 'grey', 'strip'].forEach(function(color) {
!is$2.str(String.prototype[color]) && Object.defineProperty(String.prototype, color, {
get: function() {
return String(this)
}
});
});
}
var identity = function identity(d) {
return d
};
var identity$1 = /*#__PURE__*/Object.freeze({
default: identity,
__moduleExports: identity
});
var wrap = function wrap(d){
return function(){
return d
}
};
var wrap$1 = /*#__PURE__*/Object.freeze({
default: wrap,
__moduleExports: wrap
});
var keys = function keys(o) {
return Object.keys(is$2.obj(o) || is$2.fn(o) ? o : {})
};
var keys$1 = /*#__PURE__*/Object.freeze({
default: keys,
__moduleExports: keys
});
var str = function str(d){
return d === 0 ? '0'
: !d ? ''
: is$2.fn(d) ? '' + d
: is$2.obj(d) ? JSON.stringify(d)
: String(d)
};
var str$1 = /*#__PURE__*/Object.freeze({
default: str,
__moduleExports: str
});
var wrap$2 = ( wrap$1 && wrap ) || wrap$1;
var keys$2 = ( keys$1 && keys ) || keys$1;
var str$2 = ( str$1 && str ) || str$1;
var key = function key(k, v){
var set = arguments.length > 1
, keys = is$2.fn(k) ? [] : str$2(k).split('.').filter(Boolean)
, root = keys.shift();
return function deep(o, i){
var masked = {};
return !o ? undefined
: !is$2.num(k) && !k ? (set ? replace(o, v) : o)
: is$2.arr(k) ? (k.map(copy), masked)
: o[k] || !keys.length ? (set ? ((o[k] = is$2.fn(v) ? v(o[k], i) : v), o)
: (is$2.fn(k) ? k(o) : o[k]))
: (set ? (key(keys.join('.'), v)(o[root] ? o[root] : (o[root] = {})), o)
: key(keys.join('.'))(o[root]))
function copy(k){
var val = key(k)(o);
val = is$2.fn(v) ? v(val)
: val == undefined ? v
: val;
if (val != undefined)
{ key(k, is$2.fn(val) ? wrap$2(val) : val)(masked); }
}
function replace(o, v) {
keys$2(o).map(function(k){ delete o[k]; });
keys$2(v).map(function(k){ o[k] = v[k]; });
return o
}
}
};
var key$1 = /*#__PURE__*/Object.freeze({
default: key,
__moduleExports: key
});
var key$2 = ( key$1 && key ) || key$1;
var header = function header(header$1, value) {
var getter = arguments.length == 1;
return function(d){
return !d || !d.headers ? null
: getter ? key$2(header$1)(d.headers)
: key$2(header$1)(d.headers) == value
}
};
var header$1 = /*#__PURE__*/Object.freeze({
default: header,
__moduleExports: header
});
var datum = function datum(node){
return node.__data__
};
var datum$1 = /*#__PURE__*/Object.freeze({
default: datum,
__moduleExports: datum
});
var datum$2 = ( datum$1 && datum ) || datum$1;
var from_1 = from;
from.parent = fromParent;
function from(o){
return function(k){
return key$2(k)(o)
}
}
function fromParent(k){
return datum$2(this.parentNode)[k]
}
var from$1 = /*#__PURE__*/Object.freeze({
default: from_1,
__moduleExports: from_1
});
var from$2 = ( from$1 && from_1 ) || from$1;
var values = function values(o) {
return !o ? [] : keys$2(o).map(from$2(o))
};
var values$1 = /*#__PURE__*/Object.freeze({
default: values,
__moduleExports: values
});
var to = {
arr: toArray
, obj: toObject
};
function toArray(d){
return Array.prototype.slice.call(d, 0)
}
function toObject(d) {
var by = 'id'
;
return arguments.length == 1
? (by = d, reduce)
: reduce.apply(this, arguments)
function reduce(p,v,i){
if (i === 0) { p = {}; }
p[is$2.fn(by) ? by(v, i) : v[by]] = v;
return p
}
}
var to_1 = to.arr;
var to_2 = to.obj;
var to$1 = /*#__PURE__*/Object.freeze({
default: to,
__moduleExports: to,
arr: to_1,
obj: to_2
});
var to$2 = ( to$1 && to ) || to$1;
var za = function az() {
return compare(to$2.arr(arguments))
};
function compare(keys){
return function(a, b){
if (!keys.length) { return 0 }
var k = keys[0]
, ka = key$2(k)(a) || ''
, kb = key$2(k)(b) || '';
return ka < kb ? 1
: ka > kb ? -1
: compare(keys.slice(1))(a, b)
}
}
var za$1 = /*#__PURE__*/Object.freeze({
default: za,
__moduleExports: za
});
var includes = function includes(pattern){
return function(d){
return d && d.indexOf && ~d.indexOf(pattern)
}
};
var includes$1 = /*#__PURE__*/Object.freeze({
default: includes,
__moduleExports: includes
});
var includes$2 = ( includes$1 && includes ) || includes$1;
var text = {
header: 'text/plain'
, check: function check(res){ return !includes$2('.html')(res.name) && !includes$2('.css')(res.name) && is$2.str(res.body) }
};
var text_1 = text.header;
var text_2 = text.check;
var text$1 = /*#__PURE__*/Object.freeze({
default: text,
__moduleExports: text,
header: text_1,
check: text_2
});
var owner = client$2 ? /* istanbul ignore next */ window : global;
var owner$1 = /*#__PURE__*/Object.freeze({
default: owner,
__moduleExports: owner
});
var owner$2 = ( owner$1 && owner ) || owner$1;
var err = function err(ns){
return function(d){
if (!owner$2.console || !console.error.apply) { return d; }
is$2.arr(arguments[2]) && (arguments[2] = arguments[2].length);
var args = to$2.arr(arguments)
, prefix = '[err][' + (new Date()).toISOString() + ']' + ns;
args.unshift(prefix.red ? prefix.red : prefix);
return console.error.apply(console, args), d
}
};
var err$1 = /*#__PURE__*/Object.freeze({
default: err,
__moduleExports: err
});
var log = function log(ns){
return function(d){
if (!owner$2.console || !console.log.apply) { return d; }
is$2.arr(arguments[2]) && (arguments[2] = arguments[2].length);
var args = to$2.arr(arguments)
, prefix = '[log][' + (new Date()).toISOString() + ']' + ns;
args.unshift(prefix.grey ? prefix.grey : prefix);
return console.log.apply(console, args), d
}
};
var log$1 = /*#__PURE__*/Object.freeze({
default: log,
__moduleExports: log
});
var split = function split(delimiter){
return function(d){
return d.split(delimiter)
}
};
var split$1 = /*#__PURE__*/Object.freeze({
default: split,
__moduleExports: split
});
var split$2 = ( split$1 && split ) || split$1;
var identity$2 = ( identity$1 && identity ) || identity$1;
var DEBUG = strip((client$2 ? (owner$2.location.search.match(/debug=(.*?)(&|$)/) || [])[1] : key$2('process.env.DEBUG')(owner$2)) || '')
, whitelist = DEBUG.split(',').map(split$2('/'));
var deb = function deb(ns){
return DEBUG == '*' || whitelist.some(matches(ns)) ? out : identity$2
function out(d){
if (!owner$2.console || !console.log.apply) { return d; }
is$2.arr(arguments[2]) && (arguments[2] = arguments[2].length);
var args = to$2.arr(arguments)
, prefix = '[deb][' + (new Date()).toISOString() + ']' + ns;
args.unshift(prefix.grey ? prefix.grey : prefix);
return console.log.apply(console, args), d
}
};
function matches(ns) {
ns = strip(ns).split('/');
return function(arr){
return arr.length == 1 ? arr[0] == ns[0]
: arr.length == 2 ? arr[0] == ns[0] && arr[1] == ns[1]
: false
}
}
function strip(str) {
return str.replace(/(\[|\])/g, '')
}
var deb$1 = /*#__PURE__*/Object.freeze({
default: deb,
__moduleExports: deb
});
var emitterify$2 = ( emitterify$1 && emitterify ) || emitterify$1;
var header$2 = ( header$1 && header ) || header$1;
var values$2 = ( values$1 && values ) || values$1;
var za$2 = ( za$1 && za ) || za$1;
var text$2 = ( text$1 && text ) || text$1;
var require$$0$1 = ( err$1 && err ) || err$1;
var require$$0$2 = ( log$1 && log ) || log$1;
var require$$2 = ( deb$1 && deb ) || deb$1;
// -------------------------------------------
// API: Gets or sets a resource
// -------------------------------------------
// ripple('name') - returns the resource body if it exists
// ripple('name') - creates & returns resource if it doesn't exist
// ripple('name', {}) - creates & returns resource, with specified name and body
// ripple({ ... }) - creates & returns resource, with specified name, body and headers
// ripple.resources - returns raw resources
// ripple.register - alias for ripple
// ripple.on - event listener for changes - all resources
// ripple('name').on - event listener for changes - resource-specific
var rijs_core = function core(ref){
if ( ref === void 0 ) ref = {};
var aliases = ref.aliases; if ( aliases === void 0 ) aliases = {};
log$2('creating');
ripple.resources = {};
ripple.link = link(ripple);
ripple.register = ripple;
ripple.types = types();
return linkify(emitterify$2(ripple), aliases)
function ripple(name, body, headers){
return !name ? ripple
: is$2.arr(name) ? name.map(ripple)
: is$2.promise(name) ? name.then(ripple).catch(err$2)
: is$2.obj(name) && !name.name ? ripple(values$2(name))
: is$2.fn(name) && name.resources ? ripple(values$2(name.resources))
: is$2.str(name) && !body && ripple.resources[name] ? ripple.resources[name].body
: is$2.str(name) && !body && !ripple.resources[name] ? undefined
: is$2.str(name) && body ? register(ripple)({ name: name, body: body, headers: headers })
: is$2.obj(name) ? register(ripple)(name)
: (err$2('could not find or create resource', name), false)
}
};
var register = function (ripple) { return function (ref) {
var name = ref.name;
var body = ref.body;
var headers = ref.headers; if ( headers === void 0 ) headers = {};
name = ripple.aliases.src[name] || name;
if (is$2.promise(body)) { return body.then(function (body) { return register(ripple)({ name: name, body: body, headers: headers }); }).catch(err$2) }
deb$2('registering', name);
var res = normalise(ripple)({ name: name, body: body, headers: headers });
if (!res) { return err$2('failed to register', name), false }
ripple.resources[name] = res;
ripple.emit('change', [name, {
type: 'update'
, value: res.body
, time: now(res)
}]);
return ripple.resources[name].body
}; };
var normalise = function (ripple) { return function (res) {
if (!header$2('content-type')(res)) { values$2(ripple.types).sort(za$2('priority')).some(contentType(res)); }
if (!header$2('content-type')(res)) { return err$2('could not understand resource', res), false }
return parse(ripple)(res)
}; };
var parse = function (ripple) { return function (res) {
var type = header$2('content-type')(res);
if (!ripple.types[type]) { return err$2('could not understand type', type), false }
return (ripple.types[type].parse || identity$2)(res)
}; };
var contentType = function (res) { return function (type) { return type.check(res) && (res.headers['content-type'] = type.header); }; };
var types = function () { return [text$2].reduce(to$2.obj('header'), 1); };
var linkify = function (ripple, aliases) {
ripple.aliases = { dst: {}, src: {} };
for (var name in aliases)
{ ripple.link(aliases[name], name); }
return ripple
};
var link = function (ripple) { return function (from, to) {
ripple.aliases.src[from] = to;
ripple.aliases.dst[to] = from;
Object.defineProperty(ripple.resources, from, {
get: function get(){ return ripple.resources[to] }
, set: function set(value){ ripple.resources[to] = value; }
});
}; };
var err$2 = require$$0$1('[ri/core]')
, log$2 = require$$0$2('[ri/core]')
, deb$2 = require$$2('[ri/core]')
, now = function (d, t) { return (t = key$2('body.log.length')(d), is$2.num(t) ? t - 1 : t); };
var rijs_core$1 = /*#__PURE__*/Object.freeze({
default: rijs_core,
__moduleExports: rijs_core
});
// -------------------------------------------
// Exposes a convenient global instance
// -------------------------------------------
var rijs_singleton = function singleton(ripple){
log$3('creating');
if (!owner$2.ripple) { owner$2.ripple = ripple; }
return ripple
};
var log$3 = require$$0$2('[ri/singleton]');
var rijs_singleton$1 = /*#__PURE__*/Object.freeze({
default: rijs_singleton,
__moduleExports: rijs_singleton
});
var copy = function copy(from, to){
return function(d){
return to[d] = from[d], d
}
};
var copy$1 = /*#__PURE__*/Object.freeze({
default: copy,
__moduleExports: copy
});
var copy$2 = ( copy$1 && copy ) || copy$1;
var overwrite = function overwrite(to){
return function(from){
keys$2(from)
.map(copy$2(from, to));
return to
}
};
var overwrite$1 = /*#__PURE__*/Object.freeze({
default: overwrite,
__moduleExports: overwrite
});
var not = function not(fn){
return function(){
return !fn.apply(this, arguments)
}
};
var not$1 = /*#__PURE__*/Object.freeze({
default: not,
__moduleExports: not
});
var not$2 = ( not$1 && not ) || not$1;
var extend = function extend(to){
return function(from){
keys$2(from)
.filter(not$2(is$2.in(to)))
.map(copy$2(from, to));
return to
}
};
var extend$1 = /*#__PURE__*/Object.freeze({
default: extend,
__moduleExports: extend
});
var merge_1 = merge;
function merge(to){
return function(from){
for (x in from)
{ is$2.obj(from[x]) && is$2.obj(to[x])
? merge(to[x])(from[x])
: (to[x] = from[x]); }
return to
}
}
var merge$1 = /*#__PURE__*/Object.freeze({
default: merge_1,
__moduleExports: merge_1
});
var attr = function attr(name, value) {
var args = arguments.length;
return !is$2.str(name) && args == 2 ? attr(arguments[1]).call(this, arguments[0])
: !is$2.str(name) && args == 3 ? attr(arguments[1], arguments[2]).call(this, arguments[0])
: function(el){
var ctx = this || {};
el = ctx.nodeName || is$2.fn(ctx.node) ? ctx : el;
el = el.node ? el.node() : el;
el = el.host || el;
return args > 1 && value === false ? el.removeAttribute(name)
: args > 1 ? (el.setAttribute(name, value), value)
: el.attributes.getNamedItem(name)
&& el.attributes.getNamedItem(name).value
}
};
var attr$1 = /*#__PURE__*/Object.freeze({
default: attr,
__moduleExports: attr
});
var act = { add: add, update: update, remove: remove }
, str$3 = JSON.stringify
, parse$1 = JSON.parse;
var set = function set(d, skipEmit) {
return function(o, existing, max) {
if (!is$2.obj(o) && !is$2.fn(o))
{ return o }
if (!is$2.obj(d)) {
var log = existing || o.log || []
, root = o;
if (!is$2.def(max)) { max = log.max || 0; }
if (!max) { log = []; }
if (max < 0) { log = log.concat(null); }
if (max > 0) {
var s = str$3(o);
root = parse$1(s);
log = log.concat({ type: 'update', value: parse$1(s), time: log.length });
}
def$2(log, 'max', max);
root.log
? (root.log = log)
: def$2(emitterify$2(root, null), 'log', log, 1);
return root
}
if (is$2.def(d.key)) {
if (!apply(o, d.type, (d.key = '' + d.key).split('.').filter(Boolean), d.value))
{ return false }
} else
{ return false }
if (o.log && o.log.max)
{ o.log.push((d.time = o.log.length, o.log.max > 0 ? d : null)); }
if (!skipEmit && o.emit)
{ o.emit('change', d); }
return o
}
};
function apply(body, type, path, value) {
var next = path.shift();
if (!act[type])
{ return false }
if (path.length) {
if (!(next in body))
{ if (type == 'remove') { return true }
else { body[next] = {}; } }
return apply(body[next], type, path, value)
}
else {
return !act[type](body, next, value)
}
}
function add(o, k, v) {
is$2.arr(o)
? o.splice(k, 0, v)
: (o[k] = v);
}
function update(o, k, v) {
if (!is$2.num(k) && !k) {
if (!is$2.obj(v)) { return true }
for (var x in o) { delete o[x]; }
for (var x in v) { o[x] = v[x]; }
} else
{ o[k] = v; }
}
function remove(o, k, v) {
is$2.arr(o)
? o.splice(k, 1)
: delete o[k];
}
var set$1 = /*#__PURE__*/Object.freeze({
default: set,
__moduleExports: set
});
var overwrite$2 = ( overwrite$1 && overwrite ) || overwrite$1;
var extend$2 = ( extend$1 && extend ) || extend$1;
var merge$2 = ( merge$1 && merge_1 ) || merge$1;
var attr$2 = ( attr$1 && attr ) || attr$1;
var set$2 = ( set$1 && set ) || set$1;
// -------------------------------------------
// Adds support for data resources
// -------------------------------------------
var rijs_data = function data(ripple){
log$4('creating');
ripple
.on('change.data')
.filter(function (ref) {
var name = ref[0];
var change = ref[1];
return header$2('content-type', 'application/data')(ripple.resources[name]);
})
.filter(function (ref) {
var name = ref[0];
var change = ref[1];
return change && change.key;
})
.map(function (ref) {
var name = ref[0];
var change = ref[1];
return ripple
.resources[name]
.body
.emit('change', (change || null), not$2(is$2.in(['bubble'])));
});
ripple.types['application/data'] = {
header: 'application/data'
, ext: '*.data.js'
, selector: function (res) { return ("[data~=\"" + (res.name) + "\"]"); }
, extract: function (el) { return (attr$2("data")(el) || '').split(' '); }
, check: function (res) { return is$2.obj(res.body); }
, load: function load(res) {
var exported = commonjsRequire(res.headers.path);
exported = exported.default || exported;
exported = is$2.fn(exported) ? exported(ripple) : exported;
res.headers['content-type'] = this.header;
ripple(merge$2(res)(exported));
return ripple.resources[res.name]
}
, parse: function parse(res){
var existing = ripple.resources[res.name] || {};
extend$2(res.headers)(existing.headers);
res.body = set$2()(
res.body || []
, existing.body && existing.body.log
, is$2.num(res.headers.log) ? res.headers.log : -1
);
overwrite$2(res.body.on)(listeners(existing));
res.body.on('change.bubble', function (change) {
ripple.emit('change', ripple.change = [res.name, change], not$2(is$2.in(['data'])));
delete ripple.change;
});
if (res.headers.loaded && !res.headers.loading)
{ res.headers.loading = Promise.resolve(res.headers.loaded(ripple, res))
.then(function () {
delete res.headers.loading;
return res
}); }
return res
}
};
return ripple
};
var log$4 = require$$0$2('[ri/types/data]')
, listeners = key$2('body.on');
var rijs_data$1 = /*#__PURE__*/Object.freeze({
default: rijs_data,
__moduleExports: rijs_data
});
var djbx = function (str) {
var hash = 5381
, i = str.length;
while (i)
{ hash = (hash * 33) ^ str.charCodeAt(--i); }
return hash >>> 0
};
var djbx$1 = /*#__PURE__*/Object.freeze({
default: djbx,
__moduleExports: djbx
});
var hash = ( djbx$1 && djbx ) || djbx$1;
var client_1 = function(ripple) {
return log$5("creating"), ripple.types["text/css"] = {
header: "text/css",
ext: "*.css",
selector: function (res) { return ("[css~=\"" + (res.name) + "\"]"); },
extract: function (el) { return (attr$2("css")(el) || "").split(" "); },
check: function (res) { return includes$2(".css")(res.name); },
shortname: function (path) { return basename(path); },
load: !1,
parse: function (res) { return (res.headers.hash = res.headers.hash || hash(res.body), res); }
}, ripple;
};
var log$5 = require$$0$2("[ri/types/css]");
var basename;
var client$3 = /*#__PURE__*/Object.freeze({
default: client_1,
__moduleExports: client_1
});
var lo = function lo(d){
return (d || '').toLowerCase()
};
var lo$1 = /*#__PURE__*/Object.freeze({
default: lo,
__moduleExports: lo
});
var lo$2 = ( lo$1 && lo ) || lo$1;
var client_1$1 = function(ripple, ref) {
if ( ref === void 0 ) ref = {};
var dir = ref.dir; if ( dir === void 0 ) dir = ".";
return log$6("creating"), ripple.require = (function (res) { return function (module) {
if (module in res.headers.dependencies && ripple.resources[res.headers.dependencies[module]]) { return ripple(res.headers.dependencies[module]); }
throw new Error(("Cannot find module: " + module + " for " + (res.name)));
}; }), ripple.types["application/javascript"] = {
header: header$3,
selector: function (res) { return ((res.name) + ",[is~=\"" + (res.name) + "\"]"); },
extract: function (el) { return (attr$2("is")(el) || "").split(" ").concat(lo$2(el.nodeName)); },
ext: "*.js",
shortname: function (path) { return basename$1(path).split(".").slice(0, -1).join("."); },
check: function (res) { return is$2.fn(res.body); },
load: !1,
parse: function (res) {
if ("cjs" == res.headers.format) {
var m = {
exports: {}
};
res.body(m, m.exports, ripple.require(res), {
env: {}
}), res.body = m.exports;
}
return res;
}
}, ripple;
};
var log$6 = require$$0$2("[ri/types/fn]"), header$3 = "application/javascript";
var basename$1;
var client$4 = /*#__PURE__*/Object.freeze({
default: client_1$1,
__moduleExports: client_1$1
});
var nanosocket = function(url){
if ( url === void 0 ) url = location.href.replace('http', 'ws');
var io = emitterify$2({ attempt: 0 });
io.ready = io.once('connected');
io.connect = connect(io, url);
io.connect();
io.send = function (data) { return io.ready.then(function (socket) { return socket.send(data); }); };
return io
};
var min = Math.min;
var pow = Math.pow;
var connect = function (io, url) { return function () {
var WebSocket = window.WebSocket;
var location = window.location;
var setTimeout = window.setTimeout;
var socket = new WebSocket(url);
socket.onopen = function (d) { return io.emit('connected', socket); };
socket.onmessage = function (d) { return io.emit('recv', d.data); };
socket.onclose = function (d) {
io.ready = io.once('connected');
io.emit('disconnected');
setTimeout(io.connect, backoff(++io.attempt));
};
}; };
var backoff = function (attempt, base, cap) {
if ( base === void 0 ) base = 100;
if ( cap === void 0 ) cap = 10000;
return min(cap, base * pow(2, attempt));
};
var nanosocket$1 = /*#__PURE__*/Object.freeze({
default: nanosocket,
__moduleExports: nanosocket
});
var require$$0$3 = ( nanosocket$1 && nanosocket ) || nanosocket$1;
var client$5 = function(ref){
if ( ref === void 0 ) ref = {};
var socket = ref.socket; if ( socket === void 0 ) socket = require$$0$3();
socket.id = 0;
var server = emitterify$2({
socket: socket
, send: send(socket)
, get subscriptions(){
return values$2(socket.on)
.map(function (d) { return d && d[0]; })
.filter(function (d) { return d && d.type && d.type[0] == '$'; })
}
});
socket
.once('disconnected')
.map(function (d) { return socket
.on('connected')
.map(reconnect(server)); }
);
socket
.on('recv')
.map(deserialise)
.each(function (ref) {
var id = ref.id;
var data = ref.data;
// TODO: check/warn if no sub
var sink = socket.on[("$" + id)] && socket.on[("$" + id)][0];
data.exec ? data.exec(sink, data.value)
: !id ? server.emit('recv', data)
: socket.emit(("$" + id), data);
});
return server
};
var deserialise = function (input) { return (new Function(("return " + input)))(); };
var reconnect = function (server) { return function () { return server.subscriptions
.map(function (ref) {
var subscription = ref.subscription;
return server.socket.send(subscription);
}); }; };
var send = function (socket, type) { return function (data, meta) {
if (data instanceof window.Blob)
{ return binary(socket, data, meta) }
var id = str$2(++socket.id)
, output = socket.on(("$" + id))
, next = function (data, count) {
if ( count === void 0 ) count = 0;
return socket
.send(output.source.subscription = str$2({ id: id, data: data, type: type }))
.then(function (d) { return output.emit('sent', { id: id, count: count }); });
};
data.next
? data.map(next).source.emit('start')
: next(data);
output
.source
.once('stop')
.filter(function (reason) { return reason != 'CLOSED'; })
.map(function (d) { return send(socket, 'UNSUBSCRIBE')(id)
// TODO: also force stop on close of server created sub (?)
.filter(function (d, i, n) { return n.source.emit('stop', 'CLOSED'); }); }
);
return output
}; };
var binary = function (socket, blob, meta, start, blockSize) {
if ( start === void 0 ) start = 0;
if ( blockSize === void 0 ) blockSize = 1024;
var output = emitterify$2().on('recv')
, next = function (id) { return function () { return start >= blob.size
? output.emit('sent', { id: id })
: ( socket.send(blob.slice(start, start += blockSize))
, window.setTimeout(next(id))
); }; };
send(socket, 'BINARY')({ size: blob.size, meta: meta })
.on('sent', function (ref) {
var id = ref.id;
return next(id)();
})
.on('progress', function (received) { return output.emit('progress', { received: received, total: blob.size }); })
.map(output.next)
.source
.until(output.once('stop'));
return output
};
var client$6 = /*#__PURE__*/Object.freeze({
default: client$5,
__moduleExports: client$5
});
var time = function time(ms, fn) {
return arguments.length === 1
? setTimeout(ms)
: setTimeout(fn, ms)
};
var time$1 = /*#__PURE__*/Object.freeze({
default: time,
__moduleExports: time
});
var require$$0$4 = ( client$6 && client$5 ) || client$6;
var time$2 = ( time$1 && time ) || time$1;
var client$7 = function sync(
ripple
, ref
, ref$1
){
if ( ref === void 0 ) ref = {};
if ( ref$1 === void 0 ) ref$1 = {};
var xrs = ref$1.xrs; if ( xrs === void 0 ) xrs = require$$0$4;
ripple.server = xrs();
ripple.send = send$1(ripple);
ripple.subscribe = subscribe(ripple);
ripple.subscriptions = {};
ripple.get = get(ripple);
ripple.upload = upload(ripple);
ripple.upload.id = 0;
// TODO: other than cache pushes? ans: use server.type
ripple
.server
.on('recv')
.map(function (data, i, n) { return cache(ripple)(data, i, n); });
return ripple
};
var send$1 = function (ref) {
var server = ref.server;
return function (name, type, value) { return name instanceof Blob ? server.send(name, type)
: is$2.obj(name) ? server.send(name)
: server.send({ name: name, type: type, value: value }); };
};
var get = function (ripple) { return function (name, k) { return ripple
.subscribe(name, k)
.filter(function (d, i, n) { return n.source.emit('stop'); })
.start(); }; };
var cache = function (ripple, n, k) { return function (change) {
// if (name && change.name && name != change.name) ripple.link(name, change.name)
var name = change.name = change.name || n;
if (!change.type) { change.type = 'update'; }
if (is$2.def(k)) { change.key = k + "." + (str$2(change.key)); }
!change.key && change.type == 'update'
? ripple(body(change))
: set$2(change)(ripple.resources[name] ? ripple(name) : ripple(name, {}));
ripple.change = change;
return key$2(k)(ripple(name))
}; };
var subscribe = function (ripple) { return function (name, k) {
if (is$2.arr(name)) { return merge$3(name.map(function (n) { return ripple.subscribe(n, k); }))
.map(function (d) { return name.reduce(function (p, v, i) { return (p[v] = d[i], p); }, {}); }) }
ripple.subscriptions[name] = ripple.subscriptions[name] || {};
if (is$2.arr(k)) { return merge$3(k.map(function (k) { return ripple.subscribe(name, k); }))
.map(function (d) { return key$2(k)(ripple(name)); }) }
var output = emitterify$2().on('subscription');
output
.on('stop')
.each(function (d, i, n) {
raw.subs.splice(raw.subs.indexOf(output), 1);
time$2(1000, function () {
if (raw.subs.length) { return }
raw.source.emit('stop');
ripple.subscriptions[name][k] = undefined;
output.emit('end');
});
});
if (ripple.subscriptions[name][k])
{ output
.on('start')
.map(function () { return key$2(k)(ripple(name)); })
.filter(is$2.def)
.map(function (initial) { return output.next(initial); }); }
var raw = ripple.subscriptions[name][k] = ripple.subscriptions[name][k] || ripple
.send(name, 'SUBSCRIBE', k)
.map(cache(ripple, name, k))
.each(function (value) {
raw.subs.map(function (o) { return o.next(value); });
delete ripple.change;
});
raw.subs = raw.subs || [];
raw.subs.push(output);
return output
}; };
var upload = function (ripple) { return function (name, form) {
var index = ++ripple.upload.id
, fields = {}
, size = 0
, next = function () {
if (!files.length) { return true }
var ref = files.shift();
var field = ref.field;
var filename = ref.filename;
var i = ref.i;
var blob = ref.blob;
return ripple
.send(blob, { filename: filename, field: field, i: i, index: index })
.on('progress', function (ref) {
var received = ref.received;
var total = ref.total;
return output.emit('progress', {
total: size
, received:
size
- (blob.size - received)
- files.reduce(function (acc, d) { return (acc += d.blob.size); }, 0)
});
})
.then(next)
};
var files = keys$2(form)
.map(function (field) { return (fields[field] = form[field], field); })
.filter(function (field) { return form[field] instanceof FileList; })
.map(function (field) {
fields[field] = [];
return to$2.arr(form[field])
.map(function (f) { return (size += f.size, f); })
.map(function (f, i) { return ({ field: field, filename: f.name, i: i, blob: f, sent: 0 }); })
})
.reduce(flatten$2, []);
var output = ripple.send({
files: files.length
, type: 'PREUPLOAD'
, fields: fields
, index: index
, size: size
, name: name
}).once('sent', next);
return output
}; };
var body = function (ref) {
var name = ref.name;
var value = ref.value;
var headers = ref.headers;
return ({ name: name, headers: headers, body: value });
};
// TODO: factor out
var merge$3 = function (streams) {
var output = emitterify$2().on('merged');
output.streams = streams;
streams.map(function (stream, i) { return stream.each(function (value) {
stream.latest = value;
var latest = streams.map(function (d) { return d.latest; });
if (latest.every(is$2.def)) { output.next(latest); }
}); }
);
output
.once('start')
.map(function (d) { return streams.map(function ($) { return $.source.emit('start'); }); });
output
.once('stop')
.map(function (d) { return streams.map(function ($) { return $.source.emit('stop'); }); });
return output
};
var client$8 = /*#__PURE__*/Object.freeze({
default: client$7,
__moduleExports: client$7
});
var ready = function ready(fn){
return document.body ? fn() : document.addEventListener('DOMContentLoaded', fn.bind(this))
};
var ready$1 = /*#__PURE__*/Object.freeze({
default: ready,
__moduleExports: ready
});
var _class = function (definition) { return assign$1(
definition.class ? definition.class
: !definition.prototype ? classed(definition)
: definition.prototype.render ? definition
: definition.prototype.connected ? definition
: classed(definition)
); };
var assign$1 = Object.assign;
var classed = function (render) { return render.class = render.class || class {
render(){ render.apply(this, arguments); }
}; };
var _class$1 = /*#__PURE__*/Object.freeze({
default: _class,
__moduleExports: _class
});
var event = function event(node, index) {
node = node.host && node.host.nodeName ? node.host : node;
if (node.on) { return }
node.listeners = {};
var on = function (o) {
var type = o.type.split('.').shift();
if (!node.listeners[type])
{ node.addEventListener(type, node.listeners[type] =
function (event) { return (!event.detail || !event.detail.emitted ? emit(type, event) : 0); }
); }
};
var off = function (o) {
if (!node.on[o.type].length) {
node.removeEventListener(o.type, node.listeners[o.type]);
delete node.listeners[o.type];
}
};
emitterify$2(node, { on: on, off: off });
var emit = node.emit;
node.emit = function(type, params){
var detail = { params: params, emitted: true }
, event = new CustomEvent(type, { detail: detail, bubbles: false, cancelable: true });
node.dispatchEvent(event);
return emit(type, event)
};
};
var event$1 = /*#__PURE__*/Object.freeze({
default: event,
__moduleExports: event
});
var classed$1 = ( _class$1 && _class ) || _class$1;
var event$2 = ( event$1 && event ) || event$1;
var noop$1 = function () {}
, HTMLElement = client$2 && window.HTMLElement || class {}
, registry = client$2 && window.customElements || {};
var define = function define(name, component) {
if (arguments.length == 1) { component = name, name = "anon-" + (registry.anon++); }
if (component.wrapper) { return component.wrapper }
if (!name.includes('-')) { return; }
if (!client$2) { return wrap$3(classed$1(component)) }
var wrapped = registry.get(name);
if (wrapped) {
if (wrapped.class == classed$1(component)) { return wrapped }
wrapped.class = classed$1(component);
var instances = Array.from(document.querySelectorAll(name));
instances.map(function (node) {
node.disconnectedCallback();
node.methods.map(function (method) { delete node[method]; });
node.connectedCallback();
});
} else {
registry.define(name, wrapped = wrap$3(classed$1(component)));
}
return wrapped
};
var wrap$3 = function (component) {
component.wrapper = component.wrapper || class extends HTMLElement {
connectedCallback(){
var this$1 = this;
var ref = component.wrapper.class;
var prototype = ref.prototype;
event$2(this);
this.state = this.state || {};
this.methods = Object
.getOwnPropertyNames(prototype)
.filter(function (method) { return !(method in disallowed); })
.map(function (method) { return ((this$1[method] = prototype[method].bind(this$1)), method); });
return Promise.resolve((this.connected || noop$1).call(this, this, this.state))
.then(function (d) {
this$1.initialised = true;
this$1.render();
})
}
render(){
var ref = component.wrapper.class;
var prototype = ref.prototype;
if (!this.initialised) { return }
return prototype.render.call(this, this, this.state)
}
disconnectedCallback(){
(this.disconnected || noop$1).call(this, this, this.state);
this.dispatchEvent(new CustomEvent('disconnected'));
this.initialised = false;
}
};
component.wrapper.class = component;
return component.wrapper
};
var disallowed = { length: 1, prototype: 1, name: 1, render: 1 };
registry.anon = registry.anon || 1;
var define$1 = /*#__PURE__*/Object.freeze({
default: define,
__moduleExports: define
});
var ready$2 = ( ready$1 && ready ) || ready$1;
var define$2 = ( define$1 && define ) || define$1;
var rijs_components = function components(ripple){
if (!client$2) { return ripple }
log$7('creating');
// if no render is defined on a component, load up definition
Node.prototype.render = function(){
var name = this.nodeName.toLowerCase();
if (name.includes('-'))
{ return this.fn$ = this.fn$ || ripple
.subscribe(name)
.map(function (component) { return define$2(name, component); }) }
// TODO: test this works well across all instances
// .until(new Promise(resolve => this.addEventListener('disconnected', () => {
// if (!this.isConnected) resolve()
// })))
};
// this is for backwards compatibility
Node.prototype.draw = function(){
this.render();
};
ready$2(function () { return Array.from(document.querySelectorAll('*'))
.filter(function (d) { return d.nodeName.includes('-'); })
.map(function (node) { return node.render(); }); }
);
return ripple
};
var log$7 = require$$0$2('[ri/components]');
var rijs_components$1 = /*#__PURE__*/Object.freeze({
default: rijs_components,
__moduleExports: rijs_components
});
var require$$0$5 = ( rijs_core$1 && rijs_core ) || rijs_core$1;
var require$$1 = ( rijs_singleton$1 && rijs_singleton ) || rijs_singleton$1;
var require$$2$1 = ( rijs_data$1 && rijs_data ) || rijs_data$1;
var require$$3 = ( client$3 && client_1 ) || client$3;
var require$$4 = ( client$4 && client_1$1 ) || client$4;
var require$$5 = ( client$8 && client$7 ) || client$8;
var require$$6 = ( rijs_components$1 && rijs_components ) || rijs_components$1;
var ripple = createCommonjsModule(function (module) {
function create(opts) {
var ripple = require$$0$5(opts);
return require$$1(ripple, opts), require$$2$1(ripple, opts),
require$$3(ripple, opts), require$$4(ripple, opts), require$$5(ripple, opts),
require$$6(ripple, opts), ripple;
}
!window.ripple && create(), module.exports = create;
});
return ripple;
}());
================================================
FILE: client/ripple.js
================================================
const client = require("utilise/client");
function create(opts) {
const ripple = require("rijs.core")(opts);
return require("rijs.singleton")(ripple, opts), require("rijs.data")(ripple, opts),
require("rijs.css")(ripple, opts), require("rijs.fn")(ripple, opts), require("rijs.sync")(ripple, opts),
require("rijs.components")(ripple, opts), ripple;
}
!window.ripple && create(), module.exports = create;
================================================
FILE: index.js
================================================
const client = require('utilise/client')
if (client) !window.ripple && create()
module.exports = create
function create(opts){
const ripple = require('rijs.core')(opts)
require('rijs.singleton')(ripple, opts)
require('rijs.data')(ripple, opts)
require('rijs.css')(ripple, opts)
require('rijs.fn')(ripple, opts)
require('rijs.sync')(ripple, opts)
require('rijs.components')(ripple, opts)
if (!client) {
const { dirname, resolve } = require('path')
opts.dir = opts.dir || dirname(module.parent.filename)
opts.serve = resolve(__dirname, 'client')
require('rijs.sessions')(ripple, opts)
require('rijs.serve')(ripple, opts)
require('rijs.pages')(ripple, opts)
require('rijs.resdir')(ripple, opts)
}
return ripple
}
================================================
FILE: package.json
================================================
{
"name": "rijs",
"version": "0.9.1",
"main": ".",
"author": "Pedram Emrouznejad (https://github.com/pemrouz)",
"license": "pemrouz.mit-license.org",
"repository": {
"type": "git",
"url": "git://github.com/rijs/fullstack.git"
},
"scripts": {
"clean": "rm -rf ./client/ripple.*",
"build": "npm run clean && npm run client && npm run rollup && npm run minify && npm run gzip",
"client": "uglifyjs index.js -b -d client=true -c > ./client/ripple.js",
"rollup": "rollup -c",
"minify": "uglifyjs ./client/ripple.bundle.js -m -c keep_fargs=false > ./client/ripple.min.js",
"gzip": "gzip -c ./client/ripple.min.js > ./client/ripple.min.js.gz",
"version": "npm run build && git add -A",
"postversion": "git push && git push --tags",
"test": "tap ./tests/*.js"
},
"dependencies": {
"rijs.components": "*",
"rijs.core": "*",
"rijs.css": "*",
"rijs.data": "*",
"rijs.fn": "*",
"rijs.pages": "*",
"rijs.resdir": "*",
"rijs.serve": "*",
"rijs.sessions": "*",
"rijs.singleton": "*",
"rijs.sync": "*",
"utilise": "*"
},
"devDependencies": {
"puppeteer": "^1.3.0",
"rollup": "^0.58.0",
"rollup-plugin-async": "*",
"rollup-plugin-buble": "*",
"rollup-plugin-commonjs": "*",
"rollup-plugin-node-resolve": "*",
"rollup-plugin-nodent": "*",
"tap": "^10.7.3",
"uglify-es": "^3.3.10"
}
}
================================================
FILE: rollup.config.js
================================================
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import async from 'rollup-plugin-async';
import buble from 'rollup-plugin-buble'
export default {
input: 'client/ripple.js'
, output: {
file: 'client/ripple.bundle.js'
, format: 'iife'
}
, name: 'rijs'
, plugins: [
nodeResolve({ browser: true })
, commonjs({ ignoreGlobal: true })
, async()
, buble({
transforms: {
generator: false
, classes: false
}
})
]
}
================================================
FILE: rollup.pure.config.js
================================================
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import replace from 'rollup-plugin-replace'
import buble from 'rollup-plugin-buble'
export default {
input: 'index.js'
, output: {
file: 'ripple.pure.js'
, format: 'iife'
}
, name: 'rijs'
, plugins: [
replace({
delimiters: ['','']
, values: {
"require('utilise/emitterify')": "window.emitterify"
, "require('utilise/overwrite')": "window.overwrite"
, "require('utilise/colorfill')": "window.colorfill"
, "require('utilise/includes')": "window.includes"
, "require('utilise/identity')": "window.identity"
, "require('utilise/debounce')": "window.debounce"
, "require('utilise/flatten')": "window.flatten"
, "require('utilise/replace')": "window.replace"
, "require('utilise/header')": "window.header"
, "require('utilise/extend')": "window.extend"
, "require('utilise/append')": "window.append"
, "require('utilise/values')": "window.values"
, "require('utilise/ready')": "window.ready"
, "require('utilise/proxy')": "window.proxy"
, "require('utilise/split')": "window.split"
, "require('utilise/clone')": "window.clone"
, "require('utilise/group')": "window.group"
, "require('utilise/parse')": "window.parse"
, "require('utilise/attr')": "window.attr"
, "require('utilise/keys')": "window.keys"
, "require('utilise/time')": "window.time"
, "require('utilise/noop')": "window.noop"
, "require('utilise/from')": "window.from"
, "require('utilise/all')": "window.all"
, "require('utilise/raw')": "window.raw"
, "require('utilise/log')": "window.log"
, "require('utilise/not')": "window.not"
, "require('utilise/key')": "window.key"
, "require('utilise/set')": "window.set"
, "require('utilise/err')": "window.err"
, "require('utilise/str')": "window.str"
, "require('utilise/is')": "window.is"
, "require('utilise/by')": "window.by"
, "require('utilise/el')": "window.el"
, "require('utilise/to')": "window.to"
, "require('utilise/lo')": "window.lo"
, "require('utilise/fn')": "window.fn"
, "require('utilise/za')": "window.za"
, "require('utilise/owner')": "window"
, "require('utilise/client')": "true"
, "require('rijs.sessions')": "d => d"
, "require('rijs.resdir')": "d => d"
, "require('rijs.pages')": "d => d"
, "require('rijs.serve')": "d => d"
}
})
, nodeResolve({ browser: true })
, commonjs({ ignoreGlobal: true })
, buble()
]
}
================================================
FILE: tests/basic.test.js
================================================
(async () => {
const puppeteer = require('puppeteer')
, browser = await puppeteer.launch({ headless: process.env.HEADLESS !== 'false' })
, { test } = require('tap')
await test('define, use component on page, with stylesheet, hot reload', async ({ plan, same }) => {
plan(2)
const { ripple, page } = await startup()
// register component and css
ripple
.resource('web-component', node => node.innerHTML = 'foo')
// append to page
await page.evaluate(() => {
foo = document.createElement('web-component')
document.body.appendChild(foo)
foo.render()
})
// check rendered
await page.waitFor('web-component')
same('foo', await page.evaluate(() => foo.innerHTML))
// register new version of component
ripple('web-component', node => node.innerHTML = 'boo')
same('boo', await page.evaluate(() => foo.innerHTML))
await page.close()
})
await test('auto load components, with dependencies', async ({ plan, same }) => {
plan(1)
const { ripple, page } = await startup(``)
// check rendered
await page.waitFor(() => component.innerHTML == 'foo')
same(['./resources/utils/foo.js', 'auto-loaded-component'], await page.evaluate(() => Object.keys(ripple.resources)))
await page.close()
})
await browser.close()
process.exit(0)
async function startup(body = ''){
const ripple = require('..')({ port: 0, dir: __dirname })
ripple.server.express.use((req, res) => res.send(`
${body}
`))
await ripple.server.once('listening')
const page = await browser.newPage()
await page.goto(`http://localhost:${ripple.server.port}`)
if (process.env.DEBUG == 'true')
page.on('console', (...args) => console.log('(CLIENT):', ...args))
return { ripple, page }
}
})()
================================================
FILE: tests/resources/_components/x-foo.css
================================================
:host { background: red }
================================================
FILE: tests/resources/_components/x-foo.js
================================================
const define = require('@compone/define')
, style = require('@compone/style')
module.exports = define('x-foo', async (node, state) => {
await style(node, await ripple.get('x-foo.css'))
node.innerHTML = await ripple.get('some-data')
})
================================================
FILE: tests/resources/components/auto-loaded-component.js
================================================
const foo = require('../utils/foo')
module.exports = node => (node.innerHTML = foo)
================================================
FILE: tests/resources/utils/foo.js
================================================
module.exports = 'foo'