├── .gitattributes ├── .gitignore ├── .travis.yml ├── README.md ├── client ├── ripple.bundle.js ├── ripple.js ├── ripple.min.js └── ripple.min.js.gz ├── index.js ├── package-lock.json ├── 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 /.gitattributes: -------------------------------------------------------------------------------- 1 | dist/* -diff -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | *.log -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "stable" 5 | 6 | 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 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ripple Fullstack 2 | 3 | On the server: 4 | 5 | **`index.js`** 6 | ```js 7 | const ripple = require('rijs')({ dir: __dirname }) 8 | ``` 9 | 10 | On the client: 11 | 12 | **`pages/index.html`** 13 | ```html 14 | 15 | ``` 16 | 17 | Run it: 18 | 19 | ``` 20 | $ node index.js 21 | ``` 22 | 23 | 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). 24 | 25 | Clients will then just be streamed the fine-grained resources they are using (i.e. everything is lazy loaded, no bundling, no over-fetching). 26 | 27 | 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. 28 | 29 | That's it! No boilerplate necessary, no build pipeline, no special transpilation, no magical CLI. 30 | 31 | The basic API is: 32 | 33 | ```js 34 | ripple(name) // getter 35 | ripple(name, body) // setter 36 | ripple.on('change', (name, change) => { .. }) 37 | ``` 38 | 39 |   40 | ## Components 41 | 42 | Let's add a (Web) Component to the page: 43 | 44 | **`index.html`** 45 | ```diff 46 | 47 | + 48 | ``` 49 | 50 | Let's define the component: 51 | 52 | **`resources/my-app.js:`** 53 | 54 | ```js 55 | export default () => () 56 | ``` 57 | 58 | Ripple is agnostic to _how_ you write your components, they should just be idempotent: a single render function. 59 | 60 | This is fine: 61 | 62 | **`resources/my-app.js:`** 63 | 64 | ```js 65 | export default (node, data) => node.innerHTML = 'Hello World!' 66 | ``` 67 | 68 | Or using some DOM-diff helper: 69 | 70 | **`resources/my-app.js:`** 71 | 72 | ```js 73 | export default (node, data) => jsx(node)`

Hello World

` 74 | ``` 75 | 76 | Or using [once](https://github.com/utilise/once#once)/D3 joins: 77 | 78 | **`resources/my-app.js:`** 79 | 80 | ```js 81 | export default (node, data) => { 82 | once(node) 83 | ('h1', 1) 84 | .text('Hello World') 85 | }) 86 | ``` 87 | 88 | For more info about writing idempotent components, see [this spec](https://github.com/pemrouz/vanilla). 89 | 90 |   91 | ## State/Data 92 | 93 | The first parameter of the component is the node to update. 94 | 95 | The second parameter contains all the state and data the component needs to render: 96 | 97 | ```js 98 | export default function component(node, data){ ... } 99 | ``` 100 | 101 | * You can inject data resources by adding the name of the resources to the data attribute: 102 | 103 | ```html 104 | 105 | ``` 106 | 107 | ```js 108 | export default function shop({ stock }){ ... } 109 | ``` 110 | 111 | Declaring the data needed on a component is used to reactively rerender it when the data changes. 112 | 113 | 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): 114 | 115 | ```js 116 | const dependency = await pull('dependency') 117 | ``` 118 | 119 | * The other option is to explicitly pass down data to the component from the parent: 120 | 121 | ```js 122 | once(node) 123 | ('my-shop', { stock }) 124 | ``` 125 | 126 | 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: 127 | 128 | ```js 129 | element.state = { stock } 130 | element.draw() 131 | ``` 132 | 133 |   134 | ## Defaults 135 | 136 | You can set defaults using the ES6 syntax: 137 | 138 | ```js 139 | export default function shop({ stock = [] }){ ... } 140 | ``` 141 | 142 | 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): 143 | 144 | ```js 145 | export default function shop(state){ 146 | const stock = defaults(state, 'stock', []) 147 | } 148 | ``` 149 | 150 |   151 | ## Updates 152 | 153 | #### Local state 154 | 155 | Whenever you need to update local state, just change the `state` and invoke a redraw (like a game loop): 156 | 157 | ```js 158 | export default function abacus(node, state){ 159 | const o = once(node) 160 | , { counter = 0 } = state 161 | 162 | o('span', 1) 163 | .text(counter) 164 | 165 | o('button', 1) 166 | .text('increment') 167 | .on('click.increment' d => { 168 | state.counter++ 169 | o.draw() 170 | }) 171 | } 172 | ``` 173 | 174 | #### Global state 175 | 176 | Whenever you need to update global state, you can simply compute the new value and register it again which will trigger an update: 177 | 178 | ```js 179 | ripple('stock', { 180 | apples: 10 181 | , oranges: 20 182 | , pomegranates: 30 183 | }) 184 | ``` 185 | 186 | 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: 187 | 188 | ```js 189 | update('pomegranates', 20)(ripple('stock')) 190 | // same as: set({ type: 'update', key: 'pomegranate', value: 20 })(ripple('stock')) 191 | ``` 192 | 193 | Using logs of atomic diffs combines the benefits of immutability with a saner way to synchronise state across a distributed environment. 194 | 195 | 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. 196 | 197 |   198 | ## Events 199 | 200 | Dispatch an event on the root element to communicate changes to parents (`node.dispatchEvent`). 201 | 202 |   203 | ## Routing 204 | 205 | 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: 206 | 207 | ```js 208 | export function app(node, data){ 209 | const o = once(node) 210 | , { pathname } = location 211 | 212 | o('page-dashboard', pathname == '/dashboard') 213 | o('page-login', pathname == '/login') 214 | 215 | once(window) 216 | .on('popstate.nav', d => o.draw()) 217 | } 218 | ``` 219 | 220 | This solution is not tied to any library, and you may not need one at all. 221 | 222 | For advanced uses cases, checkout [decouter](https://github.com/pemrouz/decouter). 223 | 224 |   225 | ## Styling 226 | 227 | You can author your stylesheets assuming they are completely isolated, using the Web Component syntax (`:host` etc). 228 | 229 | They will either be inserted in the shadow root of the element, or scoped and added to the head if there is no shadow. 230 | 231 | By default, the CSS resource `component-name.css` will be automatically applied to the component `component-name`. 232 | 233 | But you can apply multiple stylesheets to a component too: just extend the `css` attribute. 234 | 235 |   236 | ## Folder Convention 237 | 238 | 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. 239 | 240 | ``` 241 | resources 242 | ├── data 243 | │ ├── stock.js 244 | │ ├── order.js 245 | │ └── ... 246 | ├── my-app 247 | │ ├── my-app.js 248 | │ ├── my-app.css 249 | │ └── test.js 250 | ├── another-component 251 | │ ├── another-component.js 252 | │ ├── another-component.css 253 | │ └── test.js 254 | └── ... 255 | ``` 256 | 257 | Hot reloading works out of the box. Any changes to these files will be instantly reflected everywhere. 258 | 259 |   260 | ## Loading Resources 261 | 262 | You can also get/set resources yourselves imperatively: 263 | 264 | ```js 265 | ripple(name) // getter 266 | ripple(name, body) // setter 267 | ``` 268 | 269 | Or for example import resources from other packages: 270 | 271 | ```js 272 | ripple 273 | .resource(require('external-module-1')) 274 | .resource(require('external-module-2')) 275 | .resource(require('external-module-3')) 276 | ``` 277 | 278 | You can also create resources that proxy to [fero](https://github.com/pemrouz/fero)) services too. 279 | 280 |   281 | ## Offline 282 | 283 | Resources are currently cached in `localStorage`. 284 | 285 | This means even _before_ any network interaction, your application renders the last-known-good-state for a superfast startup. 286 | 287 | Then as resources are streamed in, the relevant parts of the application are updated. 288 | 289 | Note: Caching of resources will be improved by using ServiceWorkers under the hood instead soon ([#27](https://github.com/rijs/fullstack/issues/27)) 290 | 291 |   292 | ## Render Middleware 293 | 294 | 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: 295 | 296 | ```js 297 | // in component 298 | export default function component(node, data){ 299 | middleware(node, data) 300 | } 301 | 302 | // around component 303 | export default middleware(function component(node, data){ 304 | 305 | }) 306 | 307 | // for all components 308 | ripple.draw = middleware(ripple.draw) 309 | ``` 310 | 311 | A few useful middleware included in this build are: 312 | 313 | ### Needs 314 | 315 | [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. 316 | 317 | ```js 318 | export default { 319 | name: 'my-component' 320 | , body: function(){} 321 | , headers: { needs: '[css=..][data=..]' } 322 | } 323 | ``` 324 | 325 | ### Shadow 326 | 327 | 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. 328 | 329 | 330 | ### Perf (Optional) 331 | 332 | This one is not included by default, but you can use this to log out the time each component takes to render. 333 | 334 | Other debugging tips: 335 | 336 | * 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 }`. 337 | 338 | * Check `$0.state` on an element to see the state object it was last rendered with or manipulate it. 339 | 340 |   341 | ## Sync 342 | 343 | You can define a `from` function in the resource headers which will process requests from the client: 344 | 345 | ```js 346 | const from = (req, res) => 347 | req.data.type == 'REGISTER' ? register(req, res) 348 | : req.data.type == 'FORGOT' ? forgot(req, res) 349 | : req.data.type == 'LOGOUT' ? logout(req, res) 350 | : req.data.type == 'RESET' ? reset(req, res) 351 | : req.data.type == 'LOGIN' ? login(req, res) 352 | : false 353 | 354 | module.exports = { 355 | name: 'users' 356 | , body: {} 357 | , headers: { from } 358 | } 359 | ``` 360 | 361 | 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). 362 | 363 | 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. 364 | 365 | ```js 366 | ripple.subscribe(name, key) 367 | ripple.subscribe(name, [keys]) 368 | ``` 369 | 370 | Subscriptions are automatically deduplicated are ref-counted, so components can indepedently subscribe to the data they need without worrying about this. 371 | 372 | Note that you can also use `ripple.get` instead of subscribe if you just want to get a single value and then automatically unsubscribe. 373 | 374 |   375 | ## Ripple Minimal 376 | 377 | 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. 378 | 379 | You can also adjust your own framework by [adding/removing modules](https://github.com/rijs/minimal/blob/master/src/index.js#L1-L11). 380 | 381 |   382 | ## Docs 383 | 384 | See [rijs/docs](https://github.com/rijs/docs) for more guides, index of modules, API reference, etc 385 | -------------------------------------------------------------------------------- /client/ripple.bundle.js: -------------------------------------------------------------------------------- 1 | var rijs = (function () { 2 | 'use strict'; 3 | 4 | function commonjsRequire () { 5 | throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs'); 6 | } 7 | 8 | function createCommonjsModule(fn, module) { 9 | return module = { exports: {} }, fn(module, module.exports), module.exports; 10 | } 11 | 12 | var client = typeof window != 'undefined'; 13 | 14 | var client$1 = /*#__PURE__*/Object.freeze({ 15 | default: client, 16 | __moduleExports: client 17 | }); 18 | 19 | var promise_1 = promise; 20 | 21 | function promise() { 22 | var resolve 23 | , reject 24 | , p = new Promise(function(res, rej){ 25 | resolve = res, reject = rej; 26 | }); 27 | 28 | arguments.length && resolve(arguments[0]); 29 | p.resolve = resolve; 30 | p.reject = reject; 31 | return p 32 | } 33 | 34 | var promise$1 = /*#__PURE__*/Object.freeze({ 35 | default: promise_1, 36 | __moduleExports: promise_1 37 | }); 38 | 39 | var flatten = function flatten(p,v){ 40 | if (v instanceof Array) { v = v.reduce(flatten, []); } 41 | return (p = p || []), p.concat(v) 42 | }; 43 | 44 | var flatten$1 = /*#__PURE__*/Object.freeze({ 45 | default: flatten, 46 | __moduleExports: flatten 47 | }); 48 | 49 | var has = function has(o, k) { 50 | return k in o 51 | }; 52 | 53 | var has$1 = /*#__PURE__*/Object.freeze({ 54 | default: has, 55 | __moduleExports: has 56 | }); 57 | 58 | var has$2 = ( has$1 && has ) || has$1; 59 | 60 | var def = function def(o, p, v, w){ 61 | if (o.host && o.host.nodeName) { o = o.host; } 62 | if (p.name) { v = p, p = p.name; } 63 | !has$2(o, p) && Object.defineProperty(o, p, { value: v, writable: w }); 64 | return o[p] 65 | }; 66 | 67 | var def$1 = /*#__PURE__*/Object.freeze({ 68 | default: def, 69 | __moduleExports: def 70 | }); 71 | 72 | var promise$2 = ( promise$1 && promise_1 ) || promise$1; 73 | 74 | var flatten$2 = ( flatten$1 && flatten ) || flatten$1; 75 | 76 | var def$2 = ( def$1 && def ) || def$1; 77 | 78 | var noop = function(){}; 79 | 80 | var emitterify = function emitterify(body, hooks) { 81 | body = body || {}; 82 | hooks = hooks || {}; 83 | def$2(body, 'emit', emit, 1); 84 | def$2(body, 'once', once, 1); 85 | def$2(body, 'off', off, 1); 86 | def$2(body, 'on', on, 1); 87 | body.on['*'] = body.on['*'] || []; 88 | return body 89 | 90 | function emit(type, pm, filter) { 91 | var li = body.on[type.split('.')[0]] || [] 92 | , results = []; 93 | 94 | for (var i = 0; i < li.length; i++) 95 | { if (!li[i].ns || !filter || filter(li[i].ns)) 96 | { results.push(call(li[i].isOnce ? li.splice(i--, 1)[0] : li[i], pm)); } } 97 | 98 | for (var i = 0; i < body.on['*'].length; i++) 99 | { results.push(call(body.on['*'][i], [type, pm])); } 100 | 101 | return results.reduce(flatten$2, []) 102 | } 103 | 104 | function call(cb, pm){ 105 | return cb.next ? cb.next(pm) 106 | : pm instanceof Array ? cb.apply(body, pm) 107 | : cb.call(body, pm) 108 | } 109 | 110 | function on(type, opts, isOnce) { 111 | var id = type.split('.')[0] 112 | , ns = type.split('.')[1] 113 | , li = body.on[id] = body.on[id] || [] 114 | , cb = typeof opts == 'function' ? opts : 0; 115 | 116 | return !cb && ns ? (cb = body.on[id]['$'+ns]) ? cb : push(observable(body, opts)) 117 | : !cb && !ns ? push(observable(body, opts)) 118 | : cb && ns ? push((remove(li, body.on[id]['$'+ns] || -1), cb)) 119 | : cb && !ns ? push(cb) 120 | : false 121 | 122 | function push(cb){ 123 | cb.isOnce = isOnce; 124 | cb.type = id; 125 | if (ns) { body.on[id]['$'+(cb.ns = ns)] = cb; } 126 | li.push(cb) 127 | ;(hooks.on || noop)(cb); 128 | return cb.next ? cb : body 129 | } 130 | } 131 | 132 | function once(type, callback){ 133 | return body.on(type, callback, true) 134 | } 135 | 136 | function remove(li, cb) { 137 | var i = li.length; 138 | while (~--i) 139 | { if (cb == li[i] || cb == li[i].fn || !cb) 140 | { (hooks.off || noop)(li.splice(i, 1)[0]); } } 141 | } 142 | 143 | function off(type, cb) { 144 | remove((body.on[type] || []), cb); 145 | if (cb && cb.ns) { delete body.on[type]['$'+cb.ns]; } 146 | return body 147 | } 148 | 149 | function observable(parent, opts) { 150 | opts = opts || {}; 151 | var o = emitterify(opts.base || promise$2()); 152 | o.i = 0; 153 | o.li = []; 154 | o.fn = opts.fn; 155 | o.parent = parent; 156 | o.source = opts.fn ? o.parent.source : o; 157 | 158 | o.on('stop', function(reason){ 159 | o.type 160 | ? o.parent.off(o.type, o) 161 | : o.parent.off(o); 162 | return o.reason = reason 163 | }); 164 | 165 | o.each = function(fn) { 166 | var n = fn.next ? fn : observable(o, { fn: fn }); 167 | o.li.push(n); 168 | return n 169 | }; 170 | 171 | o.pipe = function(fn) { 172 | return fn(o) 173 | }; 174 | 175 | o.map = function(fn){ 176 | return o.each(function(d, i, n){ return n.next(fn(d, i, n)) }) 177 | }; 178 | 179 | o.filter = function(fn){ 180 | return o.each(function(d, i, n){ return fn(d, i, n) && n.next(d) }) 181 | }; 182 | 183 | o.reduce = function(fn, acc) { 184 | return o.each(function(d, i, n){ return n.next(acc = fn(acc, d, i, n)) }) 185 | }; 186 | 187 | o.unpromise = function(){ 188 | var n = observable(o, { base: {}, fn: function(d){ return n.next(d) } }); 189 | o.li.push(n); 190 | return n 191 | }; 192 | 193 | o.next = function(value) { 194 | o.resolve && o.resolve(value); 195 | return o.li.length 196 | ? o.li.map(function(n){ return n.fn(value, n.i++, n) }) 197 | : value 198 | }; 199 | 200 | o.until = function(stop){ 201 | return stop.each ? stop.each(o.stop) // TODO: check clean up on stop too 202 | : stop.then ? stop.then(o.stop) 203 | : stop.call ? o.filter(stop).map(o.stop) 204 | : 0 205 | }; 206 | 207 | o.off = function(fn){ 208 | return remove(o.li, fn), o 209 | }; 210 | 211 | o.start = function(){ 212 | o.source.emit('start'); 213 | return o 214 | }; 215 | 216 | o.stop = function(reason){ 217 | return o.source.emit('stop', reason) 218 | }; 219 | 220 | o[Symbol.asyncIterator] = function(){ 221 | return { 222 | next: function(){ 223 | return o.wait = new Promise(function(resolve){ 224 | o.wait = true; 225 | o.map(function(d, i, n){ 226 | delete o.wait; 227 | o.off(n); 228 | resolve({ value: d, done: false }); 229 | }); 230 | o.emit('pull', o); 231 | }) 232 | } 233 | } 234 | }; 235 | 236 | return o 237 | } 238 | }; 239 | 240 | var emitterify$1 = /*#__PURE__*/Object.freeze({ 241 | default: emitterify, 242 | __moduleExports: emitterify 243 | }); 244 | 245 | var is_1 = is; 246 | is.fn = isFunction; 247 | is.str = isString; 248 | is.num = isNumber; 249 | is.obj = isObject; 250 | is.lit = isLiteral; 251 | is.bol = isBoolean; 252 | is.truthy = isTruthy; 253 | is.falsy = isFalsy; 254 | is.arr = isArray; 255 | is.null = isNull; 256 | is.def = isDef; 257 | is.in = isIn; 258 | is.promise = isPromise; 259 | is.stream = isStream; 260 | 261 | function is(v){ 262 | return function(d){ 263 | return d == v 264 | } 265 | } 266 | 267 | function isFunction(d) { 268 | return typeof d == 'function' 269 | } 270 | 271 | function isBoolean(d) { 272 | return typeof d == 'boolean' 273 | } 274 | 275 | function isString(d) { 276 | return typeof d == 'string' 277 | } 278 | 279 | function isNumber(d) { 280 | return typeof d == 'number' 281 | } 282 | 283 | function isObject(d) { 284 | return typeof d == 'object' 285 | } 286 | 287 | function isLiteral(d) { 288 | return d.constructor == Object 289 | } 290 | 291 | function isTruthy(d) { 292 | return !!d == true 293 | } 294 | 295 | function isFalsy(d) { 296 | return !!d == false 297 | } 298 | 299 | function isArray(d) { 300 | return d instanceof Array 301 | } 302 | 303 | function isNull(d) { 304 | return d === null 305 | } 306 | 307 | function isDef(d) { 308 | return typeof d !== 'undefined' 309 | } 310 | 311 | function isPromise(d) { 312 | return d instanceof Promise 313 | } 314 | 315 | function isStream(d) { 316 | return !!(d && d.next) 317 | } 318 | 319 | function isIn(set) { 320 | return function(d){ 321 | return !set ? false 322 | : set.indexOf ? ~set.indexOf(d) 323 | : d in set 324 | } 325 | } 326 | 327 | var is$1 = /*#__PURE__*/Object.freeze({ 328 | default: is_1, 329 | __moduleExports: is_1 330 | }); 331 | 332 | var client$2 = ( client$1 && client ) || client$1; 333 | 334 | var is$2 = ( is$1 && is_1 ) || is$1; 335 | 336 | var colorfill_1 = colorfill(); 337 | 338 | function colorfill(){ 339 | /* istanbul ignore next */ 340 | ['red', 'green', 'bold', 'grey', 'strip'].forEach(function(color) { 341 | !is$2.str(String.prototype[color]) && Object.defineProperty(String.prototype, color, { 342 | get: function() { 343 | return String(this) 344 | } 345 | }); 346 | }); 347 | } 348 | 349 | var identity = function identity(d) { 350 | return d 351 | }; 352 | 353 | var identity$1 = /*#__PURE__*/Object.freeze({ 354 | default: identity, 355 | __moduleExports: identity 356 | }); 357 | 358 | var wrap = function wrap(d){ 359 | return function(){ 360 | return d 361 | } 362 | }; 363 | 364 | var wrap$1 = /*#__PURE__*/Object.freeze({ 365 | default: wrap, 366 | __moduleExports: wrap 367 | }); 368 | 369 | var keys = function keys(o) { 370 | return Object.keys(is$2.obj(o) || is$2.fn(o) ? o : {}) 371 | }; 372 | 373 | var keys$1 = /*#__PURE__*/Object.freeze({ 374 | default: keys, 375 | __moduleExports: keys 376 | }); 377 | 378 | var str = function str(d){ 379 | return d === 0 ? '0' 380 | : !d ? '' 381 | : is$2.fn(d) ? '' + d 382 | : is$2.obj(d) ? JSON.stringify(d) 383 | : String(d) 384 | }; 385 | 386 | var str$1 = /*#__PURE__*/Object.freeze({ 387 | default: str, 388 | __moduleExports: str 389 | }); 390 | 391 | var wrap$2 = ( wrap$1 && wrap ) || wrap$1; 392 | 393 | var keys$2 = ( keys$1 && keys ) || keys$1; 394 | 395 | var str$2 = ( str$1 && str ) || str$1; 396 | 397 | var key = function key(k, v){ 398 | var set = arguments.length > 1 399 | , keys = is$2.fn(k) ? [] : str$2(k).split('.').filter(Boolean) 400 | , root = keys.shift(); 401 | 402 | return function deep(o, i){ 403 | var masked = {}; 404 | 405 | return !o ? undefined 406 | : !is$2.num(k) && !k ? (set ? replace(o, v) : o) 407 | : is$2.arr(k) ? (k.map(copy), masked) 408 | : o[k] || !keys.length ? (set ? ((o[k] = is$2.fn(v) ? v(o[k], i) : v), o) 409 | : (is$2.fn(k) ? k(o) : o[k])) 410 | : (set ? (key(keys.join('.'), v)(o[root] ? o[root] : (o[root] = {})), o) 411 | : key(keys.join('.'))(o[root])) 412 | 413 | function copy(k){ 414 | var val = key(k)(o); 415 | val = is$2.fn(v) ? v(val) 416 | : val == undefined ? v 417 | : val; 418 | if (val != undefined) 419 | { key(k, is$2.fn(val) ? wrap$2(val) : val)(masked); } 420 | } 421 | 422 | function replace(o, v) { 423 | keys$2(o).map(function(k){ delete o[k]; }); 424 | keys$2(v).map(function(k){ o[k] = v[k]; }); 425 | return o 426 | } 427 | } 428 | }; 429 | 430 | var key$1 = /*#__PURE__*/Object.freeze({ 431 | default: key, 432 | __moduleExports: key 433 | }); 434 | 435 | var key$2 = ( key$1 && key ) || key$1; 436 | 437 | var header = function header(header$1, value) { 438 | var getter = arguments.length == 1; 439 | return function(d){ 440 | return !d || !d.headers ? null 441 | : getter ? key$2(header$1)(d.headers) 442 | : key$2(header$1)(d.headers) == value 443 | } 444 | }; 445 | 446 | var header$1 = /*#__PURE__*/Object.freeze({ 447 | default: header, 448 | __moduleExports: header 449 | }); 450 | 451 | var datum = function datum(node){ 452 | return node.__data__ 453 | }; 454 | 455 | var datum$1 = /*#__PURE__*/Object.freeze({ 456 | default: datum, 457 | __moduleExports: datum 458 | }); 459 | 460 | var datum$2 = ( datum$1 && datum ) || datum$1; 461 | 462 | var from_1 = from; 463 | from.parent = fromParent; 464 | 465 | function from(o){ 466 | return function(k){ 467 | return key$2(k)(o) 468 | } 469 | } 470 | 471 | function fromParent(k){ 472 | return datum$2(this.parentNode)[k] 473 | } 474 | 475 | var from$1 = /*#__PURE__*/Object.freeze({ 476 | default: from_1, 477 | __moduleExports: from_1 478 | }); 479 | 480 | var from$2 = ( from$1 && from_1 ) || from$1; 481 | 482 | var values = function values(o) { 483 | return !o ? [] : keys$2(o).map(from$2(o)) 484 | }; 485 | 486 | var values$1 = /*#__PURE__*/Object.freeze({ 487 | default: values, 488 | __moduleExports: values 489 | }); 490 | 491 | var to = { 492 | arr: toArray 493 | , obj: toObject 494 | }; 495 | 496 | function toArray(d){ 497 | return Array.prototype.slice.call(d, 0) 498 | } 499 | 500 | function toObject(d) { 501 | var by = 'id' 502 | ; 503 | 504 | return arguments.length == 1 505 | ? (by = d, reduce) 506 | : reduce.apply(this, arguments) 507 | 508 | function reduce(p,v,i){ 509 | if (i === 0) { p = {}; } 510 | p[is$2.fn(by) ? by(v, i) : v[by]] = v; 511 | return p 512 | } 513 | } 514 | var to_1 = to.arr; 515 | var to_2 = to.obj; 516 | 517 | var to$1 = /*#__PURE__*/Object.freeze({ 518 | default: to, 519 | __moduleExports: to, 520 | arr: to_1, 521 | obj: to_2 522 | }); 523 | 524 | var to$2 = ( to$1 && to ) || to$1; 525 | 526 | var za = function az() { 527 | return compare(to$2.arr(arguments)) 528 | }; 529 | 530 | function compare(keys){ 531 | return function(a, b){ 532 | if (!keys.length) { return 0 } 533 | var k = keys[0] 534 | , ka = key$2(k)(a) || '' 535 | , kb = key$2(k)(b) || ''; 536 | 537 | return ka < kb ? 1 538 | : ka > kb ? -1 539 | : compare(keys.slice(1))(a, b) 540 | } 541 | } 542 | 543 | var za$1 = /*#__PURE__*/Object.freeze({ 544 | default: za, 545 | __moduleExports: za 546 | }); 547 | 548 | var includes = function includes(pattern){ 549 | return function(d){ 550 | return d && d.indexOf && ~d.indexOf(pattern) 551 | } 552 | }; 553 | 554 | var includes$1 = /*#__PURE__*/Object.freeze({ 555 | default: includes, 556 | __moduleExports: includes 557 | }); 558 | 559 | var includes$2 = ( includes$1 && includes ) || includes$1; 560 | 561 | var text = { 562 | header: 'text/plain' 563 | , check: function check(res){ return !includes$2('.html')(res.name) && !includes$2('.css')(res.name) && is$2.str(res.body) } 564 | }; 565 | var text_1 = text.header; 566 | var text_2 = text.check; 567 | 568 | var text$1 = /*#__PURE__*/Object.freeze({ 569 | default: text, 570 | __moduleExports: text, 571 | header: text_1, 572 | check: text_2 573 | }); 574 | 575 | var owner = client$2 ? /* istanbul ignore next */ window : global; 576 | 577 | var owner$1 = /*#__PURE__*/Object.freeze({ 578 | default: owner, 579 | __moduleExports: owner 580 | }); 581 | 582 | var owner$2 = ( owner$1 && owner ) || owner$1; 583 | 584 | var err = function err(ns){ 585 | return function(d){ 586 | if (!owner$2.console || !console.error.apply) { return d; } 587 | is$2.arr(arguments[2]) && (arguments[2] = arguments[2].length); 588 | var args = to$2.arr(arguments) 589 | , prefix = '[err][' + (new Date()).toISOString() + ']' + ns; 590 | 591 | args.unshift(prefix.red ? prefix.red : prefix); 592 | return console.error.apply(console, args), d 593 | } 594 | }; 595 | 596 | var err$1 = /*#__PURE__*/Object.freeze({ 597 | default: err, 598 | __moduleExports: err 599 | }); 600 | 601 | var log = function log(ns){ 602 | return function(d){ 603 | if (!owner$2.console || !console.log.apply) { return d; } 604 | is$2.arr(arguments[2]) && (arguments[2] = arguments[2].length); 605 | var args = to$2.arr(arguments) 606 | , prefix = '[log][' + (new Date()).toISOString() + ']' + ns; 607 | 608 | args.unshift(prefix.grey ? prefix.grey : prefix); 609 | return console.log.apply(console, args), d 610 | } 611 | }; 612 | 613 | var log$1 = /*#__PURE__*/Object.freeze({ 614 | default: log, 615 | __moduleExports: log 616 | }); 617 | 618 | var split = function split(delimiter){ 619 | return function(d){ 620 | return d.split(delimiter) 621 | } 622 | }; 623 | 624 | var split$1 = /*#__PURE__*/Object.freeze({ 625 | default: split, 626 | __moduleExports: split 627 | }); 628 | 629 | var split$2 = ( split$1 && split ) || split$1; 630 | 631 | var identity$2 = ( identity$1 && identity ) || identity$1; 632 | 633 | var DEBUG = strip((client$2 ? (owner$2.location.search.match(/debug=(.*?)(&|$)/) || [])[1] : key$2('process.env.DEBUG')(owner$2)) || '') 634 | , whitelist = DEBUG.split(',').map(split$2('/')); 635 | 636 | var deb = function deb(ns){ 637 | return DEBUG == '*' || whitelist.some(matches(ns)) ? out : identity$2 638 | 639 | function out(d){ 640 | if (!owner$2.console || !console.log.apply) { return d; } 641 | is$2.arr(arguments[2]) && (arguments[2] = arguments[2].length); 642 | var args = to$2.arr(arguments) 643 | , prefix = '[deb][' + (new Date()).toISOString() + ']' + ns; 644 | 645 | args.unshift(prefix.grey ? prefix.grey : prefix); 646 | return console.log.apply(console, args), d 647 | } 648 | }; 649 | 650 | function matches(ns) { 651 | ns = strip(ns).split('/'); 652 | return function(arr){ 653 | return arr.length == 1 ? arr[0] == ns[0] 654 | : arr.length == 2 ? arr[0] == ns[0] && arr[1] == ns[1] 655 | : false 656 | } 657 | } 658 | 659 | function strip(str) { 660 | return str.replace(/(\[|\])/g, '') 661 | } 662 | 663 | var deb$1 = /*#__PURE__*/Object.freeze({ 664 | default: deb, 665 | __moduleExports: deb 666 | }); 667 | 668 | var emitterify$2 = ( emitterify$1 && emitterify ) || emitterify$1; 669 | 670 | var header$2 = ( header$1 && header ) || header$1; 671 | 672 | var values$2 = ( values$1 && values ) || values$1; 673 | 674 | var za$2 = ( za$1 && za ) || za$1; 675 | 676 | var text$2 = ( text$1 && text ) || text$1; 677 | 678 | var require$$0$1 = ( err$1 && err ) || err$1; 679 | 680 | var require$$0$2 = ( log$1 && log ) || log$1; 681 | 682 | var require$$2 = ( deb$1 && deb ) || deb$1; 683 | 684 | // ------------------------------------------- 685 | // API: Gets or sets a resource 686 | // ------------------------------------------- 687 | // ripple('name') - returns the resource body if it exists 688 | // ripple('name') - creates & returns resource if it doesn't exist 689 | // ripple('name', {}) - creates & returns resource, with specified name and body 690 | // ripple({ ... }) - creates & returns resource, with specified name, body and headers 691 | // ripple.resources - returns raw resources 692 | // ripple.register - alias for ripple 693 | // ripple.on - event listener for changes - all resources 694 | // ripple('name').on - event listener for changes - resource-specific 695 | 696 | var rijs_core = function core(ref){ 697 | if ( ref === void 0 ) ref = {}; 698 | var aliases = ref.aliases; if ( aliases === void 0 ) aliases = {}; 699 | 700 | log$2('creating'); 701 | 702 | ripple.resources = {}; 703 | ripple.link = link(ripple); 704 | ripple.register = ripple; 705 | ripple.types = types(); 706 | return linkify(emitterify$2(ripple), aliases) 707 | 708 | function ripple(name, body, headers){ 709 | return !name ? ripple 710 | : is$2.arr(name) ? name.map(ripple) 711 | : is$2.promise(name) ? name.then(ripple).catch(err$2) 712 | : is$2.obj(name) && !name.name ? ripple(values$2(name)) 713 | : is$2.fn(name) && name.resources ? ripple(values$2(name.resources)) 714 | : is$2.str(name) && !body && ripple.resources[name] ? ripple.resources[name].body 715 | : is$2.str(name) && !body && !ripple.resources[name] ? undefined 716 | : is$2.str(name) && body ? register(ripple)({ name: name, body: body, headers: headers }) 717 | : is$2.obj(name) ? register(ripple)(name) 718 | : (err$2('could not find or create resource', name), false) 719 | } 720 | }; 721 | 722 | var register = function (ripple) { return function (ref) { 723 | var name = ref.name; 724 | var body = ref.body; 725 | var headers = ref.headers; if ( headers === void 0 ) headers = {}; 726 | 727 | name = ripple.aliases.src[name] || name; 728 | if (is$2.promise(body)) { return body.then(function (body) { return register(ripple)({ name: name, body: body, headers: headers }); }).catch(err$2) } 729 | deb$2('registering', name); 730 | var res = normalise(ripple)({ name: name, body: body, headers: headers }); 731 | 732 | if (!res) { return err$2('failed to register', name), false } 733 | ripple.resources[name] = res; 734 | ripple.emit('change', [name, { 735 | type: 'update' 736 | , value: res.body 737 | , time: now(res) 738 | }]); 739 | 740 | return ripple.resources[name].body 741 | }; }; 742 | 743 | var normalise = function (ripple) { return function (res) { 744 | if (!header$2('content-type')(res)) { values$2(ripple.types).sort(za$2('priority')).some(contentType(res)); } 745 | if (!header$2('content-type')(res)) { return err$2('could not understand resource', res), false } 746 | return parse(ripple)(res) 747 | }; }; 748 | 749 | var parse = function (ripple) { return function (res) { 750 | var type = header$2('content-type')(res); 751 | if (!ripple.types[type]) { return err$2('could not understand type', type), false } 752 | return (ripple.types[type].parse || identity$2)(res) 753 | }; }; 754 | 755 | var contentType = function (res) { return function (type) { return type.check(res) && (res.headers['content-type'] = type.header); }; }; 756 | 757 | var types = function () { return [text$2].reduce(to$2.obj('header'), 1); }; 758 | 759 | var linkify = function (ripple, aliases) { 760 | ripple.aliases = { dst: {}, src: {} }; 761 | for (var name in aliases) 762 | { ripple.link(aliases[name], name); } 763 | return ripple 764 | }; 765 | 766 | var link = function (ripple) { return function (from, to) { 767 | ripple.aliases.src[from] = to; 768 | ripple.aliases.dst[to] = from; 769 | Object.defineProperty(ripple.resources, from, { 770 | get: function get(){ return ripple.resources[to] } 771 | , set: function set(value){ ripple.resources[to] = value; } 772 | }); 773 | }; }; 774 | 775 | var err$2 = require$$0$1('[ri/core]') 776 | , log$2 = require$$0$2('[ri/core]') 777 | , deb$2 = require$$2('[ri/core]') 778 | , now = function (d, t) { return (t = key$2('body.log.length')(d), is$2.num(t) ? t - 1 : t); }; 779 | 780 | var rijs_core$1 = /*#__PURE__*/Object.freeze({ 781 | default: rijs_core, 782 | __moduleExports: rijs_core 783 | }); 784 | 785 | // ------------------------------------------- 786 | // Exposes a convenient global instance 787 | // ------------------------------------------- 788 | var rijs_singleton = function singleton(ripple){ 789 | log$3('creating'); 790 | if (!owner$2.ripple) { owner$2.ripple = ripple; } 791 | return ripple 792 | }; 793 | 794 | var log$3 = require$$0$2('[ri/singleton]'); 795 | 796 | var rijs_singleton$1 = /*#__PURE__*/Object.freeze({ 797 | default: rijs_singleton, 798 | __moduleExports: rijs_singleton 799 | }); 800 | 801 | var copy = function copy(from, to){ 802 | return function(d){ 803 | return to[d] = from[d], d 804 | } 805 | }; 806 | 807 | var copy$1 = /*#__PURE__*/Object.freeze({ 808 | default: copy, 809 | __moduleExports: copy 810 | }); 811 | 812 | var copy$2 = ( copy$1 && copy ) || copy$1; 813 | 814 | var overwrite = function overwrite(to){ 815 | return function(from){ 816 | keys$2(from) 817 | .map(copy$2(from, to)); 818 | 819 | return to 820 | } 821 | }; 822 | 823 | var overwrite$1 = /*#__PURE__*/Object.freeze({ 824 | default: overwrite, 825 | __moduleExports: overwrite 826 | }); 827 | 828 | var not = function not(fn){ 829 | return function(){ 830 | return !fn.apply(this, arguments) 831 | } 832 | }; 833 | 834 | var not$1 = /*#__PURE__*/Object.freeze({ 835 | default: not, 836 | __moduleExports: not 837 | }); 838 | 839 | var not$2 = ( not$1 && not ) || not$1; 840 | 841 | var extend = function extend(to){ 842 | return function(from){ 843 | keys$2(from) 844 | .filter(not$2(is$2.in(to))) 845 | .map(copy$2(from, to)); 846 | 847 | return to 848 | } 849 | }; 850 | 851 | var extend$1 = /*#__PURE__*/Object.freeze({ 852 | default: extend, 853 | __moduleExports: extend 854 | }); 855 | 856 | var merge_1 = merge; 857 | 858 | function merge(to){ 859 | return function(from){ 860 | for (x in from) 861 | { is$2.obj(from[x]) && is$2.obj(to[x]) 862 | ? merge(to[x])(from[x]) 863 | : (to[x] = from[x]); } 864 | return to 865 | } 866 | } 867 | 868 | var merge$1 = /*#__PURE__*/Object.freeze({ 869 | default: merge_1, 870 | __moduleExports: merge_1 871 | }); 872 | 873 | var attr = function attr(name, value) { 874 | var args = arguments.length; 875 | 876 | return !is$2.str(name) && args == 2 ? attr(arguments[1]).call(this, arguments[0]) 877 | : !is$2.str(name) && args == 3 ? attr(arguments[1], arguments[2]).call(this, arguments[0]) 878 | : function(el){ 879 | var ctx = this || {}; 880 | el = ctx.nodeName || is$2.fn(ctx.node) ? ctx : el; 881 | el = el.node ? el.node() : el; 882 | el = el.host || el; 883 | 884 | return args > 1 && value === false ? el.removeAttribute(name) 885 | : args > 1 ? (el.setAttribute(name, value), value) 886 | : el.attributes.getNamedItem(name) 887 | && el.attributes.getNamedItem(name).value 888 | } 889 | }; 890 | 891 | var attr$1 = /*#__PURE__*/Object.freeze({ 892 | default: attr, 893 | __moduleExports: attr 894 | }); 895 | 896 | var act = { add: add, update: update, remove: remove } 897 | , str$3 = JSON.stringify 898 | , parse$1 = JSON.parse; 899 | 900 | var set = function set(d, skipEmit) { 901 | return function(o, existing, max) { 902 | if (!is$2.obj(o) && !is$2.fn(o)) 903 | { return o } 904 | 905 | if (!is$2.obj(d)) { 906 | var log = existing || o.log || [] 907 | , root = o; 908 | 909 | if (!is$2.def(max)) { max = log.max || 0; } 910 | if (!max) { log = []; } 911 | if (max < 0) { log = log.concat(null); } 912 | if (max > 0) { 913 | var s = str$3(o); 914 | root = parse$1(s); 915 | log = log.concat({ type: 'update', value: parse$1(s), time: log.length }); 916 | } 917 | 918 | def$2(log, 'max', max); 919 | 920 | root.log 921 | ? (root.log = log) 922 | : def$2(emitterify$2(root, null), 'log', log, 1); 923 | 924 | return root 925 | } 926 | 927 | if (is$2.def(d.key)) { 928 | if (!apply(o, d.type, (d.key = '' + d.key).split('.').filter(Boolean), d.value)) 929 | { return false } 930 | } else 931 | { return false } 932 | 933 | if (o.log && o.log.max) 934 | { o.log.push((d.time = o.log.length, o.log.max > 0 ? d : null)); } 935 | 936 | if (!skipEmit && o.emit) 937 | { o.emit('change', d); } 938 | 939 | return o 940 | } 941 | }; 942 | 943 | function apply(body, type, path, value) { 944 | var next = path.shift(); 945 | 946 | if (!act[type]) 947 | { return false } 948 | if (path.length) { 949 | if (!(next in body)) 950 | { if (type == 'remove') { return true } 951 | else { body[next] = {}; } } 952 | return apply(body[next], type, path, value) 953 | } 954 | else { 955 | return !act[type](body, next, value) 956 | } 957 | } 958 | 959 | function add(o, k, v) { 960 | is$2.arr(o) 961 | ? o.splice(k, 0, v) 962 | : (o[k] = v); 963 | } 964 | 965 | function update(o, k, v) { 966 | if (!is$2.num(k) && !k) { 967 | if (!is$2.obj(v)) { return true } 968 | for (var x in o) { delete o[x]; } 969 | for (var x in v) { o[x] = v[x]; } 970 | } else 971 | { o[k] = v; } 972 | } 973 | 974 | function remove(o, k, v) { 975 | is$2.arr(o) 976 | ? o.splice(k, 1) 977 | : delete o[k]; 978 | } 979 | 980 | var set$1 = /*#__PURE__*/Object.freeze({ 981 | default: set, 982 | __moduleExports: set 983 | }); 984 | 985 | var overwrite$2 = ( overwrite$1 && overwrite ) || overwrite$1; 986 | 987 | var extend$2 = ( extend$1 && extend ) || extend$1; 988 | 989 | var merge$2 = ( merge$1 && merge_1 ) || merge$1; 990 | 991 | var attr$2 = ( attr$1 && attr ) || attr$1; 992 | 993 | var set$2 = ( set$1 && set ) || set$1; 994 | 995 | // ------------------------------------------- 996 | // Adds support for data resources 997 | // ------------------------------------------- 998 | var rijs_data = function data(ripple){ 999 | log$4('creating'); 1000 | ripple 1001 | .on('change.data') 1002 | .filter(function (ref) { 1003 | var name = ref[0]; 1004 | var change = ref[1]; 1005 | 1006 | return header$2('content-type', 'application/data')(ripple.resources[name]); 1007 | }) 1008 | .filter(function (ref) { 1009 | var name = ref[0]; 1010 | var change = ref[1]; 1011 | 1012 | return change && change.key; 1013 | }) 1014 | .map(function (ref) { 1015 | var name = ref[0]; 1016 | var change = ref[1]; 1017 | 1018 | return ripple 1019 | .resources[name] 1020 | .body 1021 | .emit('change', (change || null), not$2(is$2.in(['bubble']))); 1022 | }); 1023 | 1024 | ripple.types['application/data'] = { 1025 | header: 'application/data' 1026 | , ext: '*.data.js' 1027 | , selector: function (res) { return ("[data~=\"" + (res.name) + "\"]"); } 1028 | , extract: function (el) { return (attr$2("data")(el) || '').split(' '); } 1029 | , check: function (res) { return is$2.obj(res.body); } 1030 | , load: function load(res) { 1031 | var exported = commonjsRequire(res.headers.path); 1032 | exported = exported.default || exported; 1033 | exported = is$2.fn(exported) ? exported(ripple) : exported; 1034 | res.headers['content-type'] = this.header; 1035 | ripple(merge$2(res)(exported)); 1036 | return ripple.resources[res.name] 1037 | } 1038 | , parse: function parse(res){ 1039 | var existing = ripple.resources[res.name] || {}; 1040 | 1041 | extend$2(res.headers)(existing.headers); 1042 | res.body = set$2()( 1043 | res.body || [] 1044 | , existing.body && existing.body.log 1045 | , is$2.num(res.headers.log) ? res.headers.log : -1 1046 | ); 1047 | overwrite$2(res.body.on)(listeners(existing)); 1048 | res.body.on('change.bubble', function (change) { 1049 | ripple.emit('change', ripple.change = [res.name, change], not$2(is$2.in(['data']))); 1050 | delete ripple.change; 1051 | }); 1052 | 1053 | if (res.headers.loaded && !res.headers.loading) 1054 | { res.headers.loading = Promise.resolve(res.headers.loaded(ripple, res)) 1055 | .then(function () { 1056 | delete res.headers.loading; 1057 | return res 1058 | }); } 1059 | 1060 | return res 1061 | } 1062 | }; 1063 | 1064 | return ripple 1065 | }; 1066 | 1067 | var log$4 = require$$0$2('[ri/types/data]') 1068 | , listeners = key$2('body.on'); 1069 | 1070 | var rijs_data$1 = /*#__PURE__*/Object.freeze({ 1071 | default: rijs_data, 1072 | __moduleExports: rijs_data 1073 | }); 1074 | 1075 | var djbx = function (str) { 1076 | var hash = 5381 1077 | , i = str.length; 1078 | 1079 | while (i) 1080 | { hash = (hash * 33) ^ str.charCodeAt(--i); } 1081 | 1082 | return hash >>> 0 1083 | }; 1084 | 1085 | var djbx$1 = /*#__PURE__*/Object.freeze({ 1086 | default: djbx, 1087 | __moduleExports: djbx 1088 | }); 1089 | 1090 | var hash = ( djbx$1 && djbx ) || djbx$1; 1091 | 1092 | var client_1 = function(ripple) { 1093 | return log$5("creating"), ripple.types["text/css"] = { 1094 | header: "text/css", 1095 | ext: "*.css", 1096 | selector: function (res) { return ("[css~=\"" + (res.name) + "\"]"); }, 1097 | extract: function (el) { return (attr$2("css")(el) || "").split(" "); }, 1098 | check: function (res) { return includes$2(".css")(res.name); }, 1099 | shortname: function (path) { return basename(path); }, 1100 | load: !1, 1101 | parse: function (res) { return (res.headers.hash = res.headers.hash || hash(res.body), res); } 1102 | }, ripple; 1103 | }; 1104 | 1105 | var log$5 = require$$0$2("[ri/types/css]"); 1106 | 1107 | var basename; 1108 | 1109 | var client$3 = /*#__PURE__*/Object.freeze({ 1110 | default: client_1, 1111 | __moduleExports: client_1 1112 | }); 1113 | 1114 | var lo = function lo(d){ 1115 | return (d || '').toLowerCase() 1116 | }; 1117 | 1118 | var lo$1 = /*#__PURE__*/Object.freeze({ 1119 | default: lo, 1120 | __moduleExports: lo 1121 | }); 1122 | 1123 | var lo$2 = ( lo$1 && lo ) || lo$1; 1124 | 1125 | var client_1$1 = function(ripple, ref) { 1126 | if ( ref === void 0 ) ref = {}; 1127 | var dir = ref.dir; if ( dir === void 0 ) dir = "."; 1128 | 1129 | return log$6("creating"), ripple.require = (function (res) { return function (module) { 1130 | if (module in res.headers.dependencies && ripple.resources[res.headers.dependencies[module]]) { return ripple(res.headers.dependencies[module]); } 1131 | throw new Error(("Cannot find module: " + module + " for " + (res.name))); 1132 | }; }), ripple.types["application/javascript"] = { 1133 | header: header$3, 1134 | selector: function (res) { return ((res.name) + ",[is~=\"" + (res.name) + "\"]"); }, 1135 | extract: function (el) { return (attr$2("is")(el) || "").split(" ").concat(lo$2(el.nodeName)); }, 1136 | ext: "*.js", 1137 | shortname: function (path) { return basename$1(path).split(".").slice(0, -1).join("."); }, 1138 | check: function (res) { return is$2.fn(res.body); }, 1139 | load: !1, 1140 | parse: function (res) { 1141 | if ("cjs" == res.headers.format) { 1142 | var m = { 1143 | exports: {} 1144 | }; 1145 | res.body(m, m.exports, ripple.require(res), { 1146 | env: {} 1147 | }), res.body = m.exports; 1148 | } 1149 | return res; 1150 | } 1151 | }, ripple; 1152 | }; 1153 | 1154 | var log$6 = require$$0$2("[ri/types/fn]"), header$3 = "application/javascript"; 1155 | 1156 | var basename$1; 1157 | 1158 | var client$4 = /*#__PURE__*/Object.freeze({ 1159 | default: client_1$1, 1160 | __moduleExports: client_1$1 1161 | }); 1162 | 1163 | var nanosocket = function(url){ 1164 | if ( url === void 0 ) url = location.href.replace('http', 'ws'); 1165 | 1166 | var io = emitterify$2({ attempt: 0 }); 1167 | io.ready = io.once('connected'); 1168 | io.connect = connect(io, url); 1169 | io.connect(); 1170 | io.send = function (data) { return io.ready.then(function (socket) { return socket.send(data); }); }; 1171 | return io 1172 | }; 1173 | 1174 | var min = Math.min; 1175 | var pow = Math.pow; 1176 | 1177 | var connect = function (io, url) { return function () { 1178 | var WebSocket = window.WebSocket; 1179 | var location = window.location; 1180 | var setTimeout = window.setTimeout; 1181 | var socket = new WebSocket(url); 1182 | socket.onopen = function (d) { return io.emit('connected', socket); }; 1183 | socket.onmessage = function (d) { return io.emit('recv', d.data); }; 1184 | socket.onclose = function (d) { 1185 | io.ready = io.once('connected'); 1186 | io.emit('disconnected'); 1187 | setTimeout(io.connect, backoff(++io.attempt)); 1188 | }; 1189 | }; }; 1190 | 1191 | var backoff = function (attempt, base, cap) { 1192 | if ( base === void 0 ) base = 100; 1193 | if ( cap === void 0 ) cap = 10000; 1194 | 1195 | return min(cap, base * pow(2, attempt)); 1196 | }; 1197 | 1198 | var nanosocket$1 = /*#__PURE__*/Object.freeze({ 1199 | default: nanosocket, 1200 | __moduleExports: nanosocket 1201 | }); 1202 | 1203 | var require$$0$3 = ( nanosocket$1 && nanosocket ) || nanosocket$1; 1204 | 1205 | var client$5 = function(ref){ 1206 | if ( ref === void 0 ) ref = {}; 1207 | var socket = ref.socket; if ( socket === void 0 ) socket = require$$0$3(); 1208 | 1209 | socket.id = 0; 1210 | 1211 | var server = emitterify$2({ 1212 | socket: socket 1213 | , send: send(socket) 1214 | , get subscriptions(){ 1215 | return values$2(socket.on) 1216 | .map(function (d) { return d && d[0]; }) 1217 | .filter(function (d) { return d && d.type && d.type[0] == '$'; }) 1218 | } 1219 | }); 1220 | 1221 | socket 1222 | .once('disconnected') 1223 | .map(function (d) { return socket 1224 | .on('connected') 1225 | .map(reconnect(server)); } 1226 | ); 1227 | 1228 | socket 1229 | .on('recv') 1230 | .map(deserialise) 1231 | .each(function (ref) { 1232 | var id = ref.id; 1233 | var data = ref.data; 1234 | 1235 | // TODO: check/warn if no sub 1236 | var sink = socket.on[("$" + id)] && socket.on[("$" + id)][0]; 1237 | 1238 | data.exec ? data.exec(sink, data.value) 1239 | : !id ? server.emit('recv', data) 1240 | : socket.emit(("$" + id), data); 1241 | }); 1242 | 1243 | return server 1244 | }; 1245 | 1246 | var deserialise = function (input) { return (new Function(("return " + input)))(); }; 1247 | 1248 | var reconnect = function (server) { return function () { return server.subscriptions 1249 | .map(function (ref) { 1250 | var subscription = ref.subscription; 1251 | 1252 | return server.socket.send(subscription); 1253 | }); }; }; 1254 | 1255 | 1256 | 1257 | var send = function (socket, type) { return function (data, meta) { 1258 | if (data instanceof window.Blob) 1259 | { return binary(socket, data, meta) } 1260 | 1261 | var id = str$2(++socket.id) 1262 | , output = socket.on(("$" + id)) 1263 | , next = function (data, count) { 1264 | if ( count === void 0 ) count = 0; 1265 | 1266 | return socket 1267 | .send(output.source.subscription = str$2({ id: id, data: data, type: type })) 1268 | .then(function (d) { return output.emit('sent', { id: id, count: count }); }); 1269 | }; 1270 | 1271 | data.next 1272 | ? data.map(next).source.emit('start') 1273 | : next(data); 1274 | 1275 | output 1276 | .source 1277 | .once('stop') 1278 | .filter(function (reason) { return reason != 'CLOSED'; }) 1279 | .map(function (d) { return send(socket, 'UNSUBSCRIBE')(id) 1280 | // TODO: also force stop on close of server created sub (?) 1281 | .filter(function (d, i, n) { return n.source.emit('stop', 'CLOSED'); }); } 1282 | ); 1283 | 1284 | return output 1285 | }; }; 1286 | 1287 | var binary = function (socket, blob, meta, start, blockSize) { 1288 | if ( start === void 0 ) start = 0; 1289 | if ( blockSize === void 0 ) blockSize = 1024; 1290 | 1291 | var output = emitterify$2().on('recv') 1292 | , next = function (id) { return function () { return start >= blob.size 1293 | ? output.emit('sent', { id: id }) 1294 | : ( socket.send(blob.slice(start, start += blockSize)) 1295 | , window.setTimeout(next(id)) 1296 | ); }; }; 1297 | 1298 | send(socket, 'BINARY')({ size: blob.size, meta: meta }) 1299 | .on('sent', function (ref) { 1300 | var id = ref.id; 1301 | 1302 | return next(id)(); 1303 | }) 1304 | .on('progress', function (received) { return output.emit('progress', { received: received, total: blob.size }); }) 1305 | .map(output.next) 1306 | .source 1307 | .until(output.once('stop')); 1308 | 1309 | return output 1310 | }; 1311 | 1312 | var client$6 = /*#__PURE__*/Object.freeze({ 1313 | default: client$5, 1314 | __moduleExports: client$5 1315 | }); 1316 | 1317 | var time = function time(ms, fn) { 1318 | return arguments.length === 1 1319 | ? setTimeout(ms) 1320 | : setTimeout(fn, ms) 1321 | }; 1322 | 1323 | var time$1 = /*#__PURE__*/Object.freeze({ 1324 | default: time, 1325 | __moduleExports: time 1326 | }); 1327 | 1328 | var require$$0$4 = ( client$6 && client$5 ) || client$6; 1329 | 1330 | var time$2 = ( time$1 && time ) || time$1; 1331 | 1332 | var client$7 = function sync( 1333 | ripple 1334 | , ref 1335 | , ref$1 1336 | ){ 1337 | if ( ref === void 0 ) ref = {}; 1338 | if ( ref$1 === void 0 ) ref$1 = {}; 1339 | var xrs = ref$1.xrs; if ( xrs === void 0 ) xrs = require$$0$4; 1340 | 1341 | ripple.server = xrs(); 1342 | ripple.send = send$1(ripple); 1343 | ripple.subscribe = subscribe(ripple); 1344 | ripple.subscriptions = {}; 1345 | ripple.get = get(ripple); 1346 | ripple.upload = upload(ripple); 1347 | ripple.upload.id = 0; 1348 | 1349 | // TODO: other than cache pushes? ans: use server.type 1350 | ripple 1351 | .server 1352 | .on('recv') 1353 | .map(function (data, i, n) { return cache(ripple)(data, i, n); }); 1354 | 1355 | return ripple 1356 | }; 1357 | 1358 | var send$1 = function (ref) { 1359 | var server = ref.server; 1360 | 1361 | return function (name, type, value) { return name instanceof Blob ? server.send(name, type) 1362 | : is$2.obj(name) ? server.send(name) 1363 | : server.send({ name: name, type: type, value: value }); }; 1364 | }; 1365 | 1366 | var get = function (ripple) { return function (name, k) { return ripple 1367 | .subscribe(name, k) 1368 | .filter(function (d, i, n) { return n.source.emit('stop'); }) 1369 | .start(); }; }; 1370 | 1371 | var cache = function (ripple, n, k) { return function (change) { 1372 | // if (name && change.name && name != change.name) ripple.link(name, change.name) 1373 | var name = change.name = change.name || n; 1374 | if (!change.type) { change.type = 'update'; } 1375 | if (is$2.def(k)) { change.key = k + "." + (str$2(change.key)); } 1376 | !change.key && change.type == 'update' 1377 | ? ripple(body(change)) 1378 | : set$2(change)(ripple.resources[name] ? ripple(name) : ripple(name, {})); 1379 | 1380 | ripple.change = change; 1381 | 1382 | return key$2(k)(ripple(name)) 1383 | }; }; 1384 | 1385 | var subscribe = function (ripple) { return function (name, k) { 1386 | if (is$2.arr(name)) { return merge$3(name.map(function (n) { return ripple.subscribe(n, k); })) 1387 | .map(function (d) { return name.reduce(function (p, v, i) { return (p[v] = d[i], p); }, {}); }) } 1388 | 1389 | ripple.subscriptions[name] = ripple.subscriptions[name] || {}; 1390 | if (is$2.arr(k)) { return merge$3(k.map(function (k) { return ripple.subscribe(name, k); })) 1391 | .map(function (d) { return key$2(k)(ripple(name)); }) } 1392 | var output = emitterify$2().on('subscription'); 1393 | 1394 | output 1395 | .on('stop') 1396 | .each(function (d, i, n) { 1397 | raw.subs.splice(raw.subs.indexOf(output), 1); 1398 | time$2(1000, function () { 1399 | if (raw.subs.length) { return } 1400 | raw.source.emit('stop'); 1401 | ripple.subscriptions[name][k] = undefined; 1402 | output.emit('end'); 1403 | }); 1404 | }); 1405 | 1406 | if (ripple.subscriptions[name][k]) 1407 | { output 1408 | .on('start') 1409 | .map(function () { return key$2(k)(ripple(name)); }) 1410 | .filter(is$2.def) 1411 | .map(function (initial) { return output.next(initial); }); } 1412 | 1413 | var raw = ripple.subscriptions[name][k] = ripple.subscriptions[name][k] || ripple 1414 | .send(name, 'SUBSCRIBE', k) 1415 | .map(cache(ripple, name, k)) 1416 | .each(function (value) { 1417 | raw.subs.map(function (o) { return o.next(value); }); 1418 | delete ripple.change; 1419 | }); 1420 | 1421 | raw.subs = raw.subs || []; 1422 | raw.subs.push(output); 1423 | 1424 | return output 1425 | }; }; 1426 | 1427 | var upload = function (ripple) { return function (name, form) { 1428 | var index = ++ripple.upload.id 1429 | , fields = {} 1430 | , size = 0 1431 | , next = function () { 1432 | if (!files.length) { return true } 1433 | var ref = files.shift(); 1434 | var field = ref.field; 1435 | var filename = ref.filename; 1436 | var i = ref.i; 1437 | var blob = ref.blob; 1438 | return ripple 1439 | .send(blob, { filename: filename, field: field, i: i, index: index }) 1440 | .on('progress', function (ref) { 1441 | var received = ref.received; 1442 | var total = ref.total; 1443 | 1444 | return output.emit('progress', { 1445 | total: size 1446 | , received: 1447 | size 1448 | - (blob.size - received) 1449 | - files.reduce(function (acc, d) { return (acc += d.blob.size); }, 0) 1450 | }); 1451 | }) 1452 | .then(next) 1453 | }; 1454 | 1455 | var files = keys$2(form) 1456 | .map(function (field) { return (fields[field] = form[field], field); }) 1457 | .filter(function (field) { return form[field] instanceof FileList; }) 1458 | .map(function (field) { 1459 | fields[field] = []; 1460 | return to$2.arr(form[field]) 1461 | .map(function (f) { return (size += f.size, f); }) 1462 | .map(function (f, i) { return ({ field: field, filename: f.name, i: i, blob: f, sent: 0 }); }) 1463 | }) 1464 | .reduce(flatten$2, []); 1465 | 1466 | var output = ripple.send({ 1467 | files: files.length 1468 | , type: 'PREUPLOAD' 1469 | , fields: fields 1470 | , index: index 1471 | , size: size 1472 | , name: name 1473 | }).once('sent', next); 1474 | 1475 | return output 1476 | }; }; 1477 | 1478 | var body = function (ref) { 1479 | var name = ref.name; 1480 | var value = ref.value; 1481 | var headers = ref.headers; 1482 | 1483 | return ({ name: name, headers: headers, body: value }); 1484 | }; 1485 | 1486 | // TODO: factor out 1487 | var merge$3 = function (streams) { 1488 | var output = emitterify$2().on('merged'); 1489 | output.streams = streams; 1490 | 1491 | streams.map(function (stream, i) { return stream.each(function (value) { 1492 | stream.latest = value; 1493 | var latest = streams.map(function (d) { return d.latest; }); 1494 | if (latest.every(is$2.def)) { output.next(latest); } 1495 | }); } 1496 | ); 1497 | 1498 | output 1499 | .once('start') 1500 | .map(function (d) { return streams.map(function ($) { return $.source.emit('start'); }); }); 1501 | 1502 | output 1503 | .once('stop') 1504 | .map(function (d) { return streams.map(function ($) { return $.source.emit('stop'); }); }); 1505 | 1506 | return output 1507 | }; 1508 | 1509 | var client$8 = /*#__PURE__*/Object.freeze({ 1510 | default: client$7, 1511 | __moduleExports: client$7 1512 | }); 1513 | 1514 | var ready = function ready(fn){ 1515 | return document.body ? fn() : document.addEventListener('DOMContentLoaded', fn.bind(this)) 1516 | }; 1517 | 1518 | var ready$1 = /*#__PURE__*/Object.freeze({ 1519 | default: ready, 1520 | __moduleExports: ready 1521 | }); 1522 | 1523 | var _class = function (definition) { return assign$1( 1524 | definition.class ? definition.class 1525 | : !definition.prototype ? classed(definition) 1526 | : definition.prototype.render ? definition 1527 | : definition.prototype.connected ? definition 1528 | : classed(definition) 1529 | ); }; 1530 | 1531 | var assign$1 = Object.assign; 1532 | 1533 | var classed = function (render) { return render.class = render.class || class { 1534 | render(){ render.apply(this, arguments); } 1535 | }; }; 1536 | 1537 | var _class$1 = /*#__PURE__*/Object.freeze({ 1538 | default: _class, 1539 | __moduleExports: _class 1540 | }); 1541 | 1542 | var event = function event(node, index) { 1543 | node = node.host && node.host.nodeName ? node.host : node; 1544 | if (node.on) { return } 1545 | node.listeners = {}; 1546 | 1547 | var on = function (o) { 1548 | var type = o.type.split('.').shift(); 1549 | if (!node.listeners[type]) 1550 | { node.addEventListener(type, node.listeners[type] = 1551 | function (event) { return (!event.detail || !event.detail.emitted ? emit(type, event) : 0); } 1552 | ); } 1553 | }; 1554 | 1555 | var off = function (o) { 1556 | if (!node.on[o.type].length) { 1557 | node.removeEventListener(o.type, node.listeners[o.type]); 1558 | delete node.listeners[o.type]; 1559 | } 1560 | }; 1561 | 1562 | emitterify$2(node, { on: on, off: off }); 1563 | var emit = node.emit; 1564 | 1565 | node.emit = function(type, params){ 1566 | var detail = { params: params, emitted: true } 1567 | , event = new CustomEvent(type, { detail: detail, bubbles: false, cancelable: true }); 1568 | node.dispatchEvent(event); 1569 | return emit(type, event) 1570 | }; 1571 | }; 1572 | 1573 | var event$1 = /*#__PURE__*/Object.freeze({ 1574 | default: event, 1575 | __moduleExports: event 1576 | }); 1577 | 1578 | var classed$1 = ( _class$1 && _class ) || _class$1; 1579 | 1580 | var event$2 = ( event$1 && event ) || event$1; 1581 | 1582 | var noop$1 = function () {} 1583 | , HTMLElement = client$2 && window.HTMLElement || class {} 1584 | , registry = client$2 && window.customElements || {}; 1585 | 1586 | var define = function define(name, component) { 1587 | if (arguments.length == 1) { component = name, name = "anon-" + (registry.anon++); } 1588 | if (component.wrapper) { return component.wrapper } 1589 | if (!name.includes('-')) { return; } 1590 | if (!client$2) { return wrap$3(classed$1(component)) } 1591 | var wrapped = registry.get(name); 1592 | 1593 | if (wrapped) { 1594 | if (wrapped.class == classed$1(component)) { return wrapped } 1595 | wrapped.class = classed$1(component); 1596 | var instances = Array.from(document.querySelectorAll(name)); 1597 | instances.map(function (node) { 1598 | node.disconnectedCallback(); 1599 | node.methods.map(function (method) { delete node[method]; }); 1600 | node.connectedCallback(); 1601 | }); 1602 | } else { 1603 | registry.define(name, wrapped = wrap$3(classed$1(component))); 1604 | } 1605 | 1606 | return wrapped 1607 | }; 1608 | 1609 | var wrap$3 = function (component) { 1610 | component.wrapper = component.wrapper || class extends HTMLElement { 1611 | connectedCallback(){ 1612 | var this$1 = this; 1613 | 1614 | var ref = component.wrapper.class; 1615 | var prototype = ref.prototype; 1616 | event$2(this); 1617 | this.state = this.state || {}; 1618 | this.methods = Object 1619 | .getOwnPropertyNames(prototype) 1620 | .filter(function (method) { return !(method in disallowed); }) 1621 | .map(function (method) { return ((this$1[method] = prototype[method].bind(this$1)), method); }); 1622 | 1623 | return Promise.resolve((this.connected || noop$1).call(this, this, this.state)) 1624 | .then(function (d) { 1625 | this$1.initialised = true; 1626 | this$1.render(); 1627 | }) 1628 | } 1629 | 1630 | render(){ 1631 | var ref = component.wrapper.class; 1632 | var prototype = ref.prototype; 1633 | if (!this.initialised) { return } 1634 | return prototype.render.call(this, this, this.state) 1635 | } 1636 | 1637 | disconnectedCallback(){ 1638 | (this.disconnected || noop$1).call(this, this, this.state); 1639 | this.dispatchEvent(new CustomEvent('disconnected')); 1640 | this.initialised = false; 1641 | } 1642 | }; 1643 | 1644 | component.wrapper.class = component; 1645 | return component.wrapper 1646 | }; 1647 | 1648 | var disallowed = { length: 1, prototype: 1, name: 1, render: 1 }; 1649 | 1650 | registry.anon = registry.anon || 1; 1651 | 1652 | var define$1 = /*#__PURE__*/Object.freeze({ 1653 | default: define, 1654 | __moduleExports: define 1655 | }); 1656 | 1657 | var ready$2 = ( ready$1 && ready ) || ready$1; 1658 | 1659 | var define$2 = ( define$1 && define ) || define$1; 1660 | 1661 | var rijs_components = function components(ripple){ 1662 | if (!client$2) { return ripple } 1663 | log$7('creating'); 1664 | 1665 | // if no render is defined on a component, load up definition 1666 | Node.prototype.render = function(){ 1667 | var name = this.nodeName.toLowerCase(); 1668 | if (name.includes('-')) 1669 | { return this.fn$ = this.fn$ || ripple 1670 | .subscribe(name) 1671 | .map(function (component) { return define$2(name, component); }) } 1672 | // TODO: test this works well across all instances 1673 | // .until(new Promise(resolve => this.addEventListener('disconnected', () => { 1674 | // if (!this.isConnected) resolve() 1675 | // }))) 1676 | }; 1677 | 1678 | // this is for backwards compatibility 1679 | Node.prototype.draw = function(){ 1680 | this.render(); 1681 | }; 1682 | 1683 | ready$2(function () { return Array.from(document.querySelectorAll('*')) 1684 | .filter(function (d) { return d.nodeName.includes('-'); }) 1685 | .map(function (node) { return node.render(); }); } 1686 | ); 1687 | 1688 | return ripple 1689 | }; 1690 | 1691 | var log$7 = require$$0$2('[ri/components]'); 1692 | 1693 | var rijs_components$1 = /*#__PURE__*/Object.freeze({ 1694 | default: rijs_components, 1695 | __moduleExports: rijs_components 1696 | }); 1697 | 1698 | var require$$0$5 = ( rijs_core$1 && rijs_core ) || rijs_core$1; 1699 | 1700 | var require$$1 = ( rijs_singleton$1 && rijs_singleton ) || rijs_singleton$1; 1701 | 1702 | var require$$2$1 = ( rijs_data$1 && rijs_data ) || rijs_data$1; 1703 | 1704 | var require$$3 = ( client$3 && client_1 ) || client$3; 1705 | 1706 | var require$$4 = ( client$4 && client_1$1 ) || client$4; 1707 | 1708 | var require$$5 = ( client$8 && client$7 ) || client$8; 1709 | 1710 | var require$$6 = ( rijs_components$1 && rijs_components ) || rijs_components$1; 1711 | 1712 | var ripple = createCommonjsModule(function (module) { 1713 | function create(opts) { 1714 | var ripple = require$$0$5(opts); 1715 | return require$$1(ripple, opts), require$$2$1(ripple, opts), 1716 | require$$3(ripple, opts), require$$4(ripple, opts), require$$5(ripple, opts), 1717 | require$$6(ripple, opts), ripple; 1718 | } 1719 | 1720 | !window.ripple && create(), module.exports = create; 1721 | }); 1722 | 1723 | return ripple; 1724 | 1725 | }()); 1726 | -------------------------------------------------------------------------------- /client/ripple.js: -------------------------------------------------------------------------------- 1 | const client = require("utilise/client"); 2 | 3 | function create(opts) { 4 | const ripple = require("rijs.core")(opts); 5 | return require("rijs.singleton")(ripple, opts), require("rijs.data")(ripple, opts), 6 | require("rijs.css")(ripple, opts), require("rijs.fn")(ripple, opts), require("rijs.sync")(ripple, opts), 7 | require("rijs.components")(ripple, opts), ripple; 8 | } 9 | 10 | !window.ripple && create(), module.exports = create; 11 | -------------------------------------------------------------------------------- /client/ripple.min.js: -------------------------------------------------------------------------------- 1 | var rijs=function(){"use strict";var e="undefined"!=typeof window,n=Object.freeze({default:e,__moduleExports:e}),t=function(){var e,n,t=new Promise(function(t,r){e=t,n=r});return arguments.length&&e(arguments[0]),t.resolve=e,t.reject=n,t};var r=Object.freeze({default:t,__moduleExports:t}),o=function e(n,t){return t instanceof Array&&(t=t.reduce(e,[])),(n=n||[]).concat(t)},u=Object.freeze({default:o,__moduleExports:o}),i=function(e,n){return n in e},c=Object.freeze({default:i,__moduleExports:i}),s=c&&i||c,a=function(e,n,t,r){return e.host&&e.host.nodeName&&(e=e.host),n.name&&(t=n,n=n.name),!s(e,n)&&Object.defineProperty(e,n,{value:t,writable:r}),e[n]},f=Object.freeze({default:a,__moduleExports:a}),l=r&&t||r,d=u&&o||u,p=f&&a||f,m=function(){},h=function e(n,t){return t=t||{},p(n=n||{},"emit",function(e,t,o){for(var u=n.on[e.split(".")[0]]||[],i=[],c=0;c1,o=j.fn(n)?[]:L(n).split(".").filter(Boolean),u=o.shift();return function(i,c){var s={};return i?j.num(n)||n?j.arr(n)?(n.map(function(n){var r=e(n)(i);null!=(r=j.fn(t)?t(r):null==r?t:r)&&e(n,j.fn(r)?A(r):r)(s)}),s):i[n]||!o.length?r?(i[n]=j.fn(t)?t(i[n],c):t,i):j.fn(n)?n(i):i[n]:r?(e(o.join("."),t)(i[u]?i[u]:i[u]={}),i):e(o.join("."))(i[u]):r?function(e,n){return $(e).map(function(n){delete e[n]}),$(n).map(function(t){e[t]=n[t]}),e}(i,t):i:void 0}},B=Object.freeze({default:P,__moduleExports:P}),D=B&&P||B,I=function(e,n){var t=1==arguments.length;return function(r){return r&&r.headers?t?D(e)(r.headers):D(e)(r.headers)==n:null}},q=Object.freeze({default:I,__moduleExports:I}),T=function(e){return e.__data__},U=Object.freeze({default:T,__moduleExports:T}),M=U&&T||U,R=J;function J(e){return function(n){return D(n)(e)}}J.parent=function(e){return M(this.parentNode)[e]};var F=Object.freeze({default:R,__moduleExports:R}),G=F&&R||F,H=function(e){return e?$(e).map(G(e)):[]},W=Object.freeze({default:H,__moduleExports:H}),Y={arr:function(e){return Array.prototype.slice.call(e,0)},obj:function(e){var n="id";return 1==arguments.length?(n=e,t):t.apply(this,arguments);function t(e,t,r){return 0===r&&(e={}),e[j.fn(n)?n(t,r):t[n]]=t,e}}};var K=Y.arr,Q=Y.obj,V=Object.freeze({default:Y,__moduleExports:Y,arr:K,obj:Q}),X=V&&Y||V,Z=function(){return function e(n){return function(t,r){if(!n.length)return 0;var o=n[0],u=D(o)(t)||"",i=D(o)(r)||"";return ui?-1:e(n.slice(1))(t,r)}}(X.arr(arguments))};var ee=Object.freeze({default:Z,__moduleExports:Z}),ne=function(e){return function(n){return n&&n.indexOf&&~n.indexOf(e)}},te=Object.freeze({default:ne,__moduleExports:ne}),re=te&&ne||te,oe={header:"text/plain",check:function(e){return!re(".html")(e.name)&&!re(".css")(e.name)&&j.str(e.body)}},ue=oe.header,ie=oe.check,ce=Object.freeze({default:oe,__moduleExports:oe,header:ue,check:ie}),se=_?window:global,ae=Object.freeze({default:se,__moduleExports:se}),fe=ae&&se||ae,le=function(e){return function(n){if(!fe.console||!console.error.apply)return n;j.arr(arguments[2])&&(arguments[2]=arguments[2].length);var t=X.arr(arguments),r="[err]["+(new Date).toISOString()+"]"+e;return t.unshift(r.red?r.red:r),console.error.apply(console,t),n}},de=Object.freeze({default:le,__moduleExports:le}),pe=function(e){return function(n){if(!fe.console||!console.log.apply)return n;j.arr(arguments[2])&&(arguments[2]=arguments[2].length);var t=X.arr(arguments),r="[log]["+(new Date).toISOString()+"]"+e;return t.unshift(r.grey?r.grey:r),console.log.apply(console,t),n}},me=Object.freeze({default:pe,__moduleExports:pe}),he=function(e){return function(n){return n.split(e)}},be=Object.freeze({default:he,__moduleExports:he}),ve=be&&he||be,ye=E&&O||E,ge=je((_?(fe.location.search.match(/debug=(.*?)(&|$)/)||[])[1]:D("process.env.DEBUG")(fe))||""),xe=ge.split(",").map(ve("/")),_e=function(e){return"*"==ge||xe.some(function(e){return e=je(e).split("/"),function(n){return 1==n.length?n[0]==e[0]:2==n.length&&n[0]==e[0]&&n[1]==e[1]}}(e))?function(n){if(!fe.console||!console.log.apply)return n;j.arr(arguments[2])&&(arguments[2]=arguments[2].length);var t=X.arr(arguments),r="[deb]["+(new Date).toISOString()+"]"+e;return t.unshift(r.grey?r.grey:r),console.log.apply(console,t),n}:ye};function je(e){return e.replace(/(\[|\])/g,"")}var Oe=Object.freeze({default:_e,__moduleExports:_e}),Ee=b&&h||b,ze=q&&I||q,we=W&&H||W,ke=ee&&Z||ee,Se=ce&&oe||ce,Ne=me&&pe||me,Ce=Oe&&_e||Oe,Ae=function(e){void 0===e&&(e={});var n=e.aliases;return void 0===n&&(n={}),Ue("creating"),t.resources={},t.link=qe(t),t.register=t,t.types=De(),Ie(Ee(t),n);function t(e,n,r){return e?j.arr(e)?e.map(t):j.promise(e)?e.then(t).catch(Te):j.obj(e)&&!e.name?t(we(e)):j.fn(e)&&e.resources?t(we(e.resources)):j.str(e)&&!n&&t.resources[e]?t.resources[e].body:!j.str(e)||n||t.resources[e]?j.str(e)&&n?$e(t)({name:e,body:n,headers:r}):j.obj(e)?$e(t)(e):(Te("could not find or create resource",e),!1):void 0:t}},$e=function(e){return function(n){var t=n.name,r=n.body,o=n.headers;if(void 0===o&&(o={}),t=e.aliases.src[t]||t,j.promise(r))return r.then(function(n){return $e(e)({name:t,body:n,headers:o})}).catch(Te);Me("registering",t);var u=Le(e)({name:t,body:r,headers:o});return u?(e.resources[t]=u,e.emit("change",[t,{type:"update",value:u.body,time:Re(u)}]),e.resources[t].body):(Te("failed to register",t),!1)}},Le=function(e){return function(n){return ze("content-type")(n)||we(e.types).sort(ke("priority")).some(Be(n)),ze("content-type")(n)?Pe(e)(n):(Te("could not understand resource",n),!1)}},Pe=function(e){return function(n){var t=ze("content-type")(n);return e.types[t]?(e.types[t].parse||ye)(n):(Te("could not understand type",t),!1)}},Be=function(e){return function(n){return n.check(e)&&(e.headers["content-type"]=n.header)}},De=function(){return[Se].reduce(X.obj("header"),1)},Ie=function(e,n){for(var t in e.aliases={dst:{},src:{}},n)e.link(n[t],t);return e},qe=function(e){return function(n,t){e.aliases.src[n]=t,e.aliases.dst[t]=n,Object.defineProperty(e.resources,n,{get:function(){return e.resources[t]},set:function(n){e.resources[t]=n}})}},Te=(de&&le||de)("[ri/core]"),Ue=Ne("[ri/core]"),Me=Ce("[ri/core]"),Re=function(e,n){return n=D("body.log.length")(e),j.num(n)?n-1:n},Je=Object.freeze({default:Ae,__moduleExports:Ae}),Fe=function(e){return Ge("creating"),fe.ripple||(fe.ripple=e),e},Ge=Ne("[ri/singleton]"),He=Object.freeze({default:Fe,__moduleExports:Fe}),We=function(e,n){return function(t){return n[t]=e[t],t}},Ye=Object.freeze({default:We,__moduleExports:We}),Ke=Ye&&We||Ye,Qe=function(e){return function(n){return $(n).map(Ke(n,e)),e}},Ve=Object.freeze({default:Qe,__moduleExports:Qe}),Xe=function(e){return function(){return!e.apply(this,arguments)}},Ze=Object.freeze({default:Xe,__moduleExports:Xe}),en=Ze&&Xe||Ze,nn=function(e){return function(n){return $(n).filter(en(j.in(e))).map(Ke(n,e)),e}},tn=Object.freeze({default:nn,__moduleExports:nn}),rn=function e(n){return function(t){for(x in t)j.obj(t[x])&&j.obj(n[x])?e(n[x])(t[x]):n[x]=t[x];return n}};var on=Object.freeze({default:rn,__moduleExports:rn}),un=function e(n,t){var r=arguments.length;return j.str(n)||2!=r?j.str(n)||3!=r?function(e){var o=this||{};return e=(e=(e=o.nodeName||j.fn(o.node)?o:e).node?e.node():e).host||e,r>1&&!1===t?e.removeAttribute(n):r>1?(e.setAttribute(n,t),t):e.attributes.getNamedItem(n)&&e.attributes.getNamedItem(n).value}:e(arguments[1],arguments[2]).call(this,arguments[0]):e(arguments[1]).call(this,arguments[0])},cn=Object.freeze({default:un,__moduleExports:un}),sn={add:function(e,n,t){j.arr(e)?e.splice(n,0,t):e[n]=t},update:function(e,n,t){if(j.num(n)||n)e[n]=t;else{if(!j.obj(t))return!0;for(var r in e)delete e[r];for(var r in t)e[r]=t[r]}},remove:function(e,n){j.arr(e)?e.splice(n,1):delete e[n]}},an=JSON.stringify,fn=JSON.parse,ln=function(e,n){return function(t,r,o){if(!j.obj(t)&&!j.fn(t))return t;if(!j.obj(e)){var u=r||t.log||[],i=t;if(j.def(o)||(o=u.max||0),o||(u=[]),o<0&&(u=u.concat(null)),o>0){var c=an(t);i=fn(c),u=u.concat({type:"update",value:fn(c),time:u.length})}return p(u,"max",o),i.log?i.log=u:p(Ee(i,null),"log",u,1),i}return!!j.def(e.key)&&(!!function e(n,t,r,o){var u=r.shift();if(!sn[t])return!1;if(r.length){if(!(u in n)){if("remove"==t)return!0;n[u]={}}return e(n[u],t,r,o)}return!sn[t](n,u,o)}(t,e.type,(e.key=""+e.key).split(".").filter(Boolean),e.value)&&(t.log&&t.log.max&&t.log.push((e.time=t.log.length,t.log.max>0?e:null)),!n&&t.emit&&t.emit("change",e),t))}};var dn=Object.freeze({default:ln,__moduleExports:ln}),pn=Ve&&Qe||Ve,mn=tn&&nn||tn,hn=on&&rn||on,bn=cn&&un||cn,vn=dn&&ln||dn,yn=function(e){return gn("creating"),e.on("change.data").filter(function(n){var t=n[0];n[1];return ze("content-type","application/data")(e.resources[t])}).filter(function(e){e[0];var n=e[1];return n&&n.key}).map(function(n){var t=n[0],r=n[1];return e.resources[t].body.emit("change",r||null,en(j.in(["bubble"])))}),e.types["application/data"]={header:"application/data",ext:"*.data.js",selector:function(e){return'[data~="'+e.name+'"]'},extract:function(e){return(bn("data")(e)||"").split(" ")},check:function(e){return j.obj(e.body)},load:function(n){var t=function(){throw new Error("Dynamic requires are not currently supported by rollup-plugin-commonjs")}(n.headers.path);return t=t.default||t,t=j.fn(t)?t(e):t,n.headers["content-type"]=this.header,e(hn(n)(t)),e.resources[n.name]},parse:function(n){var t=e.resources[n.name]||{};return mn(n.headers)(t.headers),n.body=vn()(n.body||[],t.body&&t.body.log,j.num(n.headers.log)?n.headers.log:-1),pn(n.body.on)(xn(t)),n.body.on("change.bubble",function(t){e.emit("change",e.change=[n.name,t],en(j.in(["data"]))),delete e.change}),n.headers.loaded&&!n.headers.loading&&(n.headers.loading=Promise.resolve(n.headers.loaded(e,n)).then(function(){return delete n.headers.loading,n})),n}},e},gn=Ne("[ri/types/data]"),xn=D("body.on"),_n=Object.freeze({default:yn,__moduleExports:yn}),jn=function(e){for(var n=5381,t=e.length;t;)n=33*n^e.charCodeAt(--t);return n>>>0},On=Object.freeze({default:jn,__moduleExports:jn}),En=On&&jn||On,zn=function(e){return wn("creating"),e.types["text/css"]={header:"text/css",ext:"*.css",selector:function(e){return'[css~="'+e.name+'"]'},extract:function(e){return(bn("css")(e)||"").split(" ")},check:function(e){return re(".css")(e.name)},shortname:function(e){return(void 0)(e)},load:!1,parse:function(e){return e.headers.hash=e.headers.hash||En(e.body),e}},e},wn=Ne("[ri/types/css]"),kn=Object.freeze({default:zn,__moduleExports:zn}),Sn=function(e){return(e||"").toLowerCase()},Nn=Object.freeze({default:Sn,__moduleExports:Sn}),Cn=Nn&&Sn||Nn,An=function(e,n){void 0===n&&(n={});var t=n.dir;return void 0===t&&(t="."),$n("creating"),e.require=function(n){return function(t){if(t in n.headers.dependencies&&e.resources[n.headers.dependencies[t]])return e(n.headers.dependencies[t]);throw new Error("Cannot find module: "+t+" for "+n.name)}},e.types["application/javascript"]={header:Ln,selector:function(e){return e.name+',[is~="'+e.name+'"]'},extract:function(e){return(bn("is")(e)||"").split(" ").concat(Cn(e.nodeName))},ext:"*.js",shortname:function(e){return(void 0)(e).split(".").slice(0,-1).join(".")},check:function(e){return j.fn(e.body)},load:!1,parse:function(n){if("cjs"==n.headers.format){var t={exports:{}};n.body(t,t.exports,e.require(n),{env:{}}),n.body=t.exports}return n}},e},$n=Ne("[ri/types/fn]"),Ln="application/javascript",Pn=Object.freeze({default:An,__moduleExports:An}),Bn=function(e){void 0===e&&(e=location.href.replace("http","ws"));var n=Ee({attempt:0});return n.ready=n.once("connected"),n.connect=qn(n,e),n.connect(),n.send=function(e){return n.ready.then(function(n){return n.send(e)})},n},Dn=Math.min,In=Math.pow,qn=function(e,n){return function(){var t=window.WebSocket,r=(window.location,window.setTimeout),o=new t(n);o.onopen=function(){return e.emit("connected",o)},o.onmessage=function(n){return e.emit("recv",n.data)},o.onclose=function(){e.ready=e.once("connected"),e.emit("disconnected"),r(e.connect,Tn(++e.attempt))}}},Tn=function(e,n,t){return void 0===n&&(n=100),void 0===t&&(t=1e4),Dn(t,n*In(2,e))},Un=Object.freeze({default:Bn,__moduleExports:Bn}),Mn=Un&&Bn||Un,Rn=function(e){void 0===e&&(e={});var n=e.socket;void 0===n&&(n=Mn()),n.id=0;var t=Ee({socket:n,send:Gn(n),get subscriptions(){return we(n.on).map(function(e){return e&&e[0]}).filter(function(e){return e&&e.type&&"$"==e.type[0]})}});return n.once("disconnected").map(function(){return n.on("connected").map(Fn(t))}),n.on("recv").map(Jn).each(function(e){var r=e.id,o=e.data,u=n.on["$"+r]&&n.on["$"+r][0];o.exec?o.exec(u,o.value):r?n.emit("$"+r,o):t.emit("recv",o)}),t},Jn=function(e){return new Function("return "+e)()},Fn=function(e){return function(){return e.subscriptions.map(function(n){var t=n.subscription;return e.socket.send(t)})}},Gn=function(e,n){return function(t,r){if(t instanceof window.Blob)return Hn(e,t,r);var o=L(++e.id),u=e.on("$"+o),i=function(t,r){return void 0===r&&(r=0),e.send(u.source.subscription=L({id:o,data:t,type:n})).then(function(){return u.emit("sent",{id:o,count:r})})};return t.next?t.map(i).source.emit("start"):i(t),u.source.once("stop").filter(function(e){return"CLOSED"!=e}).map(function(){return Gn(e,"UNSUBSCRIBE")(o).filter(function(e,n,t){return t.source.emit("stop","CLOSED")})}),u}},Hn=function(e,n,t,r,o){void 0===r&&(r=0),void 0===o&&(o=1024);var u=Ee().on("recv"),i=function(t){return function(){return r>=n.size?u.emit("sent",{id:t}):(e.send(n.slice(r,r+=o)),window.setTimeout(i(t)))}};return Gn(e,"BINARY")({size:n.size,meta:t}).on("sent",function(e){var n=e.id;return i(n)()}).on("progress",function(e){return u.emit("progress",{received:e,total:n.size})}).map(u.next).source.until(u.once("stop")),u},Wn=Object.freeze({default:Rn,__moduleExports:Rn}),Yn=function(e,n){return 1===arguments.length?setTimeout(e):setTimeout(n,e)},Kn=Object.freeze({default:Yn,__moduleExports:Yn}),Qn=Wn&&Rn||Wn,Vn=Kn&&Yn||Kn,Xn=function(e,n,t){void 0===n&&(n={}),void 0===t&&(t={});var r=t.xrs;return void 0===r&&(r=Qn),e.server=r(),e.send=Zn(e),e.subscribe=tt(e),e.subscriptions={},e.get=et(e),e.upload=rt(e),e.upload.id=0,e.server.on("recv").map(function(n,t,r){return nt(e)(n,t,r)}),e},Zn=function(e){var n=e.server;return function(e,t,r){return e instanceof Blob?n.send(e,t):j.obj(e)?n.send(e):n.send({name:e,type:t,value:r})}},et=function(e){return function(n,t){return e.subscribe(n,t).filter(function(e,n,t){return t.source.emit("stop")}).start()}},nt=function(e,n,t){return function(r){var o=r.name=r.name||n;return r.type||(r.type="update"),j.def(t)&&(r.key=t+"."+L(r.key)),r.key||"update"!=r.type?vn(r)(e.resources[o]?e(o):e(o,{})):e(ot(r)),e.change=r,D(t)(e(o))}},tt=function(e){return function(n,t){if(j.arr(n))return ut(n.map(function(n){return e.subscribe(n,t)})).map(function(e){return n.reduce(function(n,t,r){return n[t]=e[r],n},{})});if(e.subscriptions[n]=e.subscriptions[n]||{},j.arr(t))return ut(t.map(function(t){return e.subscribe(n,t)})).map(function(){return D(t)(e(n))});var r=Ee().on("subscription");r.on("stop").each(function(){o.subs.splice(o.subs.indexOf(r),1),Vn(1e3,function(){o.subs.length||(o.source.emit("stop"),e.subscriptions[n][t]=void 0,r.emit("end"))})}),e.subscriptions[n][t]&&r.on("start").map(function(){return D(t)(e(n))}).filter(j.def).map(function(e){return r.next(e)});var o=e.subscriptions[n][t]=e.subscriptions[n][t]||e.send(n,"SUBSCRIBE",t).map(nt(e,n,t)).each(function(n){o.subs.map(function(e){return e.next(n)}),delete e.change});return o.subs=o.subs||[],o.subs.push(r),r}},rt=function(e){return function(n,t){var r=++e.upload.id,o={},u=0,i=function(){if(!c.length)return!0;var n=c.shift(),t=n.field,o=n.filename,a=n.i,f=n.blob;return e.send(f,{filename:o,field:t,i:a,index:r}).on("progress",function(e){var n=e.received;e.total;return s.emit("progress",{total:u,received:u-(f.size-n)-c.reduce(function(e,n){return e+n.blob.size},0)})}).then(i)},c=$(t).map(function(e){return o[e]=t[e],e}).filter(function(e){return t[e]instanceof FileList}).map(function(e){return o[e]=[],X.arr(t[e]).map(function(e){return u+=e.size,e}).map(function(n,t){return{field:e,filename:n.name,i:t,blob:n,sent:0}})}).reduce(d,[]),s=e.send({files:c.length,type:"PREUPLOAD",fields:o,index:r,size:u,name:n}).once("sent",i);return s}},ot=function(e){var n=e.name,t=e.value;return{name:n,headers:e.headers,body:t}},ut=function(e){var n=Ee().on("merged");return n.streams=e,e.map(function(t){return t.each(function(r){t.latest=r;var o=e.map(function(e){return e.latest});o.every(j.def)&&n.next(o)})}),n.once("start").map(function(){return e.map(function(e){return e.source.emit("start")})}),n.once("stop").map(function(){return e.map(function(e){return e.source.emit("stop")})}),n},it=Object.freeze({default:Xn,__moduleExports:Xn}),ct=function(e){return document.body?e():document.addEventListener("DOMContentLoaded",e.bind(this))},st=Object.freeze({default:ct,__moduleExports:ct}),at=function(e){return ft(e.class?e.class:e.prototype?e.prototype.render?e:e.prototype.connected?e:lt(e):lt(e))},ft=Object.assign,lt=function(e){return e.class=e.class||class{render(){e.apply(this,arguments)}}},dt=Object.freeze({default:at,__moduleExports:at}),pt=function(e){if(!(e=e.host&&e.host.nodeName?e.host:e).on){e.listeners={};Ee(e,{on:function(t){var r=t.type.split(".").shift();e.listeners[r]||e.addEventListener(r,e.listeners[r]=function(e){return e.detail&&e.detail.emitted?0:n(r,e)})},off:function(n){e.on[n.type].length||(e.removeEventListener(n.type,e.listeners[n.type]),delete e.listeners[n.type])}});var n=e.emit;e.emit=function(t,r){var o=new CustomEvent(t,{detail:{params:r,emitted:!0},bubbles:!1,cancelable:!0});return e.dispatchEvent(o),n(t,o)}}},mt=Object.freeze({default:pt,__moduleExports:pt}),ht=dt&&at||dt,bt=mt&&pt||mt,vt=function(){},yt=_&&window.HTMLElement||class{},gt=_&&window.customElements||{},xt=function(e,n){if(1==arguments.length&&(n=e,e="anon-"+gt.anon++),n.wrapper)return n.wrapper;if(e.includes("-")){if(!_)return _t(ht(n));var t=gt.get(e);if(t){if(t.class==ht(n))return t;t.class=ht(n),Array.from(document.querySelectorAll(e)).map(function(e){e.disconnectedCallback(),e.methods.map(function(n){delete e[n]}),e.connectedCallback()})}else gt.define(e,t=_t(ht(n)));return t}},_t=function(e){return e.wrapper=e.wrapper||class extends yt{connectedCallback(){var n=this,t=e.wrapper.class.prototype;return bt(this),this.state=this.state||{},this.methods=Object.getOwnPropertyNames(t).filter(function(e){return!(e in jt)}).map(function(e){return n[e]=t[e].bind(n),e}),Promise.resolve((this.connected||vt).call(this,this,this.state)).then(function(){n.initialised=!0,n.render()})}render(){var n=e.wrapper.class.prototype;if(this.initialised)return n.render.call(this,this,this.state)}disconnectedCallback(){(this.disconnected||vt).call(this,this,this.state),this.dispatchEvent(new CustomEvent("disconnected")),this.initialised=!1}},e.wrapper.class=e,e.wrapper},jt={length:1,prototype:1,name:1,render:1};gt.anon=gt.anon||1;var Ot,Et=Object.freeze({default:xt,__moduleExports:xt}),zt=st&&ct||st,wt=Et&&xt||Et,kt=function(e){return _?(St("creating"),Node.prototype.render=function(){var n=this.nodeName.toLowerCase();if(n.includes("-"))return this.fn$=this.fn$||e.subscribe(n).map(function(e){return wt(n,e)})},Node.prototype.draw=function(){this.render()},zt(function(){return Array.from(document.querySelectorAll("*")).filter(function(e){return e.nodeName.includes("-")}).map(function(e){return e.render()})}),e):e},St=Ne("[ri/components]"),Nt=Object.freeze({default:kt,__moduleExports:kt}),Ct=Je&&Ae||Je,At=He&&Fe||He,$t=_n&&yn||_n,Lt=kn&&zn||kn,Pt=Pn&&An||Pn,Bt=it&&Xn||it,Dt=Nt&&kt||Nt;return function(e){function n(e){var n=Ct(e);return At(n,e),$t(n,e),Lt(n,e),Pt(n,e),Bt(n,e),Dt(n,e),n}!window.ripple&&n(),e.exports=n}(Ot={exports:{}},Ot.exports),Ot.exports}(); 2 | -------------------------------------------------------------------------------- /client/ripple.min.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rijs/fullstack/82f6e5ebe4a5c73471137a16142f519bc0aa3394/client/ripple.min.js.gz -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const client = require('utilise/client') 2 | 3 | if (client) !window.ripple && create() 4 | 5 | module.exports = create 6 | 7 | function create(opts){ 8 | const ripple = require('rijs.core')(opts) 9 | require('rijs.singleton')(ripple, opts) 10 | require('rijs.data')(ripple, opts) 11 | require('rijs.css')(ripple, opts) 12 | require('rijs.fn')(ripple, opts) 13 | require('rijs.sync')(ripple, opts) 14 | require('rijs.components')(ripple, opts) 15 | 16 | if (!client) { 17 | const { dirname, resolve } = require('path') 18 | opts.dir = opts.dir || dirname(module.parent.filename) 19 | opts.serve = resolve(__dirname, 'client') 20 | require('rijs.sessions')(ripple, opts) 21 | require('rijs.serve')(ripple, opts) 22 | require('rijs.pages')(ripple, opts) 23 | require('rijs.resdir')(ripple, opts) 24 | } 25 | 26 | return ripple 27 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rijs", 3 | "version": "0.9.1", 4 | "main": ".", 5 | "author": "Pedram Emrouznejad (https://github.com/pemrouz)", 6 | "license": "pemrouz.mit-license.org", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/rijs/fullstack.git" 10 | }, 11 | "scripts": { 12 | "clean": "rm -rf ./client/ripple.*", 13 | "build": "npm run clean && npm run client && npm run rollup && npm run minify && npm run gzip", 14 | "client": "uglifyjs index.js -b -d client=true -c > ./client/ripple.js", 15 | "rollup": "rollup -c", 16 | "minify": "uglifyjs ./client/ripple.bundle.js -m -c keep_fargs=false > ./client/ripple.min.js", 17 | "gzip": "gzip -c ./client/ripple.min.js > ./client/ripple.min.js.gz", 18 | "version": "npm run build && git add -A", 19 | "postversion": "git push && git push --tags", 20 | "test": "tap ./tests/*.js" 21 | }, 22 | "dependencies": { 23 | "rijs.components": "*", 24 | "rijs.core": "*", 25 | "rijs.css": "*", 26 | "rijs.data": "*", 27 | "rijs.fn": "*", 28 | "rijs.pages": "*", 29 | "rijs.resdir": "*", 30 | "rijs.serve": "*", 31 | "rijs.sessions": "*", 32 | "rijs.singleton": "*", 33 | "rijs.sync": "*", 34 | "utilise": "*" 35 | }, 36 | "devDependencies": { 37 | "puppeteer": "^1.3.0", 38 | "rollup": "^0.58.0", 39 | "rollup-plugin-async": "*", 40 | "rollup-plugin-buble": "*", 41 | "rollup-plugin-commonjs": "*", 42 | "rollup-plugin-node-resolve": "*", 43 | "rollup-plugin-nodent": "*", 44 | "tap": "^10.7.3", 45 | "uglify-es": "^3.3.10" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from 'rollup-plugin-node-resolve'; 2 | import commonjs from 'rollup-plugin-commonjs'; 3 | import async from 'rollup-plugin-async'; 4 | import buble from 'rollup-plugin-buble' 5 | 6 | export default { 7 | input: 'client/ripple.js' 8 | , output: { 9 | file: 'client/ripple.bundle.js' 10 | , format: 'iife' 11 | } 12 | , name: 'rijs' 13 | , plugins: [ 14 | nodeResolve({ browser: true }) 15 | , commonjs({ ignoreGlobal: true }) 16 | , async() 17 | , buble({ 18 | transforms: { 19 | generator: false 20 | , classes: false 21 | } 22 | }) 23 | ] 24 | } -------------------------------------------------------------------------------- /rollup.pure.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from 'rollup-plugin-node-resolve' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import replace from 'rollup-plugin-replace' 4 | import buble from 'rollup-plugin-buble' 5 | 6 | export default { 7 | input: 'index.js' 8 | , output: { 9 | file: 'ripple.pure.js' 10 | , format: 'iife' 11 | } 12 | , name: 'rijs' 13 | , plugins: [ 14 | replace({ 15 | delimiters: ['',''] 16 | , values: { 17 | "require('utilise/emitterify')": "window.emitterify" 18 | , "require('utilise/overwrite')": "window.overwrite" 19 | , "require('utilise/colorfill')": "window.colorfill" 20 | , "require('utilise/includes')": "window.includes" 21 | , "require('utilise/identity')": "window.identity" 22 | , "require('utilise/debounce')": "window.debounce" 23 | , "require('utilise/flatten')": "window.flatten" 24 | , "require('utilise/replace')": "window.replace" 25 | , "require('utilise/header')": "window.header" 26 | , "require('utilise/extend')": "window.extend" 27 | , "require('utilise/append')": "window.append" 28 | , "require('utilise/values')": "window.values" 29 | , "require('utilise/ready')": "window.ready" 30 | , "require('utilise/proxy')": "window.proxy" 31 | , "require('utilise/split')": "window.split" 32 | , "require('utilise/clone')": "window.clone" 33 | , "require('utilise/group')": "window.group" 34 | , "require('utilise/parse')": "window.parse" 35 | , "require('utilise/attr')": "window.attr" 36 | , "require('utilise/keys')": "window.keys" 37 | , "require('utilise/time')": "window.time" 38 | , "require('utilise/noop')": "window.noop" 39 | , "require('utilise/from')": "window.from" 40 | , "require('utilise/all')": "window.all" 41 | , "require('utilise/raw')": "window.raw" 42 | , "require('utilise/log')": "window.log" 43 | , "require('utilise/not')": "window.not" 44 | , "require('utilise/key')": "window.key" 45 | , "require('utilise/set')": "window.set" 46 | , "require('utilise/err')": "window.err" 47 | , "require('utilise/str')": "window.str" 48 | , "require('utilise/is')": "window.is" 49 | , "require('utilise/by')": "window.by" 50 | , "require('utilise/el')": "window.el" 51 | , "require('utilise/to')": "window.to" 52 | , "require('utilise/lo')": "window.lo" 53 | , "require('utilise/fn')": "window.fn" 54 | , "require('utilise/za')": "window.za" 55 | , "require('utilise/owner')": "window" 56 | , "require('utilise/client')": "true" 57 | 58 | , "require('rijs.sessions')": "d => d" 59 | , "require('rijs.resdir')": "d => d" 60 | , "require('rijs.pages')": "d => d" 61 | , "require('rijs.serve')": "d => d" 62 | } 63 | }) 64 | , nodeResolve({ browser: true }) 65 | , commonjs({ ignoreGlobal: true }) 66 | , buble() 67 | ] 68 | } -------------------------------------------------------------------------------- /tests/basic.test.js: -------------------------------------------------------------------------------- 1 | (async () => { 2 | const puppeteer = require('puppeteer') 3 | , browser = await puppeteer.launch({ headless: process.env.HEADLESS !== 'false' }) 4 | , { test } = require('tap') 5 | 6 | await test('define, use component on page, with stylesheet, hot reload', async ({ plan, same }) => { 7 | plan(2) 8 | const { ripple, page } = await startup() 9 | 10 | // register component and css 11 | ripple 12 | .resource('web-component', node => node.innerHTML = 'foo') 13 | 14 | // append to page 15 | await page.evaluate(() => { 16 | foo = document.createElement('web-component') 17 | document.body.appendChild(foo) 18 | foo.render() 19 | }) 20 | 21 | // check rendered 22 | await page.waitFor('web-component') 23 | same('foo', await page.evaluate(() => foo.innerHTML)) 24 | 25 | // register new version of component 26 | ripple('web-component', node => node.innerHTML = 'boo') 27 | same('boo', await page.evaluate(() => foo.innerHTML)) 28 | 29 | await page.close() 30 | }) 31 | 32 | await test('auto load components, with dependencies', async ({ plan, same }) => { 33 | plan(1) 34 | const { ripple, page } = await startup(``) 35 | 36 | // check rendered 37 | await page.waitFor(() => component.innerHTML == 'foo') 38 | same(['./resources/utils/foo.js', 'auto-loaded-component'], await page.evaluate(() => Object.keys(ripple.resources))) 39 | 40 | await page.close() 41 | }) 42 | 43 | await browser.close() 44 | process.exit(0) 45 | 46 | async function startup(body = ''){ 47 | const ripple = require('..')({ port: 0, dir: __dirname }) 48 | ripple.server.express.use((req, res) => res.send(` 49 | 50 | ${body} 51 | `)) 52 | 53 | await ripple.server.once('listening') 54 | 55 | const page = await browser.newPage() 56 | 57 | await page.goto(`http://localhost:${ripple.server.port}`) 58 | 59 | if (process.env.DEBUG == 'true') 60 | page.on('console', (...args) => console.log('(CLIENT):', ...args)) 61 | 62 | return { ripple, page } 63 | } 64 | })() -------------------------------------------------------------------------------- /tests/resources/_components/x-foo.css: -------------------------------------------------------------------------------- 1 | :host { background: red } -------------------------------------------------------------------------------- /tests/resources/_components/x-foo.js: -------------------------------------------------------------------------------- 1 | const define = require('@compone/define') 2 | , style = require('@compone/style') 3 | 4 | module.exports = define('x-foo', async (node, state) => { 5 | await style(node, await ripple.get('x-foo.css')) 6 | 7 | node.innerHTML = await ripple.get('some-data') 8 | }) -------------------------------------------------------------------------------- /tests/resources/components/auto-loaded-component.js: -------------------------------------------------------------------------------- 1 | const foo = require('../utils/foo') 2 | 3 | module.exports = node => (node.innerHTML = foo) -------------------------------------------------------------------------------- /tests/resources/utils/foo.js: -------------------------------------------------------------------------------- 1 | module.exports = 'foo' --------------------------------------------------------------------------------