@webqit/webflo 0.11.21 → 0.11.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -12
- package/package.json +1 -1
- package/src/runtime-pi/client/Runtime.js +31 -15
- package/test/index.test.js +6 -5
package/README.md
CHANGED
|
@@ -7,25 +7,31 @@
|
|
|
7
7
|
|
|
8
8
|
<!-- /BADGES -->
|
|
9
9
|
|
|
10
|
-
Webflo is a universal *web*, *mobile*, and *API backend* framework
|
|
10
|
+
Webflo is a universal *web*, *mobile*, and *API backend* framework that gets it all done in vanilla HTML, CSS, and JavaScript! It's a powerful little thing written to facilitate building more authentic, web-native applications!
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Here, we've put all of that up for a 10min straight read!
|
|
13
|
+
|
|
14
|
+
TL;DR: here's what's ahead...
|
|
15
|
+
|
|
16
|
+
+ web-native development and the vanilla advantage!
|
|
17
|
+
+ the path of least engineering!
|
|
13
18
|
|
|
14
19
|
## The Catch...
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
Webflo is a framework on its own track - working and thinking in vanilla HTML, CSS and JavaScript! Instead of trying to follow certain norms, it takes a plunge to draw on native web platform features - plus some more futurisric, fascinating stuffs we're proposing as standards! This means that you also have to be excited about taking a plunge to happily meet Webflo!
|
|
17
22
|
|
|
18
23
|
## The Wins...
|
|
19
24
|
|
|
20
25
|
Much of what eludes the web today...
|
|
21
26
|
|
|
22
|
-
+
|
|
23
|
-
+
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
+ Universal-everything!
|
|
27
|
+
+ the long-missing framework design and architecture for a HTML-first thinking!
|
|
28
|
+
+ a focused standards-based philosophy that breeds more authentic applications!
|
|
29
|
+
|
|
30
|
+
Plus native support for how you want to work...
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
+ a new approach to reactivity that's based on no syntax at all but plain old JavaScript!
|
|
33
|
+
+ a new "imports" feature for HTML that makes HTML more reusable!
|
|
34
|
+
+ and much more.
|
|
29
35
|
|
|
30
36
|
## Documentation
|
|
31
37
|
|
|
@@ -767,7 +773,7 @@ Here, you are able to define reusable contents in a `<template>` element...
|
|
|
767
773
|
</body>
|
|
768
774
|
```
|
|
769
775
|
|
|
770
|
-
The *module* element - `<template>` - is able to load its contents from a remote `.html` file that serves as a bundle:
|
|
776
|
+
The *module* element - `<template>` - is also able to load its contents from a remote `.html` file that serves as a bundle:
|
|
771
777
|
|
|
772
778
|
```html
|
|
773
779
|
<!--
|
|
@@ -859,7 +865,7 @@ public/products
|
|
|
859
865
|
|
|
860
866
|
#### In a Single Page Layout
|
|
861
867
|
|
|
862
|
-
In a Single Page layout (as seen [earlier](#layout-and-templating-overview)), page-specific contents - e.g. main sections - are typically bundled together into one `bundle.html` file that can be embedded on the document root.
|
|
868
|
+
In a Single Page layout (as seen [earlier](#layout-and-templating-overview)), page-specific contents - e.g. main sections - are typically bundled together into one `bundle.html` file that can be embedded on the document root. Notice how nested routes end up as nested `<template>` elements that form the equivalent of the application's URL structure.
|
|
863
869
|
|
|
864
870
|
```html
|
|
865
871
|
<!--
|
|
@@ -1258,7 +1264,7 @@ Observer.observe(document.state, 'data', e => {
|
|
|
1258
1264
|
|
|
1259
1265
|
#### The `document.state.url` Object
|
|
1260
1266
|
|
|
1261
|
-
This is a *live* object that reperesents the properties of the application URL at any point in time. The object exposes the same URL properties as
|
|
1267
|
+
This is a *live* object that reperesents the properties of the application URL at any point in time. The object exposes the same URL properties as of a standard [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) object, but, here, as *live* properties that can be observed as navigation happens, and modified to initiate navigation - all using the [Observer API](#the-observer-api).
|
|
1262
1268
|
|
|
1263
1269
|
```js
|
|
1264
1270
|
console.log(document.state.url) // { hash, host, hostname, href, origin, password, pathname, port, protocol, search, searchParams, username }
|
package/package.json
CHANGED
|
@@ -52,7 +52,6 @@ export default class Runtime {
|
|
|
52
52
|
* @return void
|
|
53
53
|
*/
|
|
54
54
|
constructor(cx, clientCallback) {
|
|
55
|
-
|
|
56
55
|
// ---------------
|
|
57
56
|
this.cx = cx;
|
|
58
57
|
this.clients = new Map;
|
|
@@ -97,12 +96,12 @@ export default class Runtime {
|
|
|
97
96
|
// Capture all link-clicks
|
|
98
97
|
// and fire to this router.
|
|
99
98
|
window.addEventListener('click', e => {
|
|
100
|
-
var
|
|
101
|
-
if (!
|
|
102
|
-
if (!
|
|
99
|
+
var anchorEl = e.target.closest('a');
|
|
100
|
+
if (!anchorEl || !anchorEl.href) return;
|
|
101
|
+
if (!anchorEl.target && !anchorEl.download && this.isSpaRoute(anchorEl, e)) {
|
|
103
102
|
// Publish everything, including hash
|
|
104
|
-
this.go(Url.copy(
|
|
105
|
-
if (!
|
|
103
|
+
this.go(Url.copy(anchorEl), {}, { src: anchorEl, srcType: 'link', });
|
|
104
|
+
if (!this.isHashAction(anchorEl)) {
|
|
106
105
|
e.preventDefault();
|
|
107
106
|
}
|
|
108
107
|
}
|
|
@@ -143,7 +142,7 @@ export default class Runtime {
|
|
|
143
142
|
method: submitParams.method,
|
|
144
143
|
body: formData,
|
|
145
144
|
}, { ...submitParams, src: form, srcType: 'form', });
|
|
146
|
-
if (!
|
|
145
|
+
if (!this.isHashAction(actionEl)) {
|
|
147
146
|
e.preventDefault();
|
|
148
147
|
}
|
|
149
148
|
}
|
|
@@ -188,8 +187,14 @@ export default class Runtime {
|
|
|
188
187
|
return window.history;
|
|
189
188
|
}
|
|
190
189
|
|
|
191
|
-
// Check is-
|
|
192
|
-
|
|
190
|
+
// Check is-hash-action
|
|
191
|
+
isHashAction(urlObj) {
|
|
192
|
+
const isHashNav = _before(window.document.location.href, '#') === _before(urlObj.href, '#') && urlObj.href.includes('#');
|
|
193
|
+
return isHashNav && urlObj.hash.length > 1 && document.querySelector(urlObj.hash);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Check is-spa-route
|
|
197
|
+
isSpaRoute(url, e = undefined) {
|
|
193
198
|
url = typeof url === 'string' ? new whatwag.URL(url) : url;
|
|
194
199
|
if (url.origin && url.origin !== this.location.origin) return false;
|
|
195
200
|
if (e && (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey)) return false;
|
|
@@ -278,13 +283,14 @@ export default class Runtime {
|
|
|
278
283
|
// ------------
|
|
279
284
|
if (response.redirected) {
|
|
280
285
|
Observer.set(this.location, { href: response.url }, { detail: { redirected: true }, });
|
|
286
|
+
Observer.set(this.network, 'requesting', null);
|
|
281
287
|
} else if (![302, 301].includes(finalResponse.status)) {
|
|
282
|
-
Observer.set(this.location, url);
|
|
288
|
+
Observer.set(this.location, Url.copy(url)/* copy() is important */);
|
|
289
|
+
Observer.set(this.network, 'requesting', null);
|
|
283
290
|
}
|
|
284
291
|
// ------------
|
|
285
292
|
// States
|
|
286
293
|
// ------------
|
|
287
|
-
Observer.set(this.network, 'requesting', null);
|
|
288
294
|
if (['link', 'form'].includes(detail.srcType)) {
|
|
289
295
|
detail.src.state && (detail.src.state.active = false);
|
|
290
296
|
detail.submitter && detail.submitter.state && (detail.submitter.state.active = false);
|
|
@@ -330,10 +336,20 @@ export default class Runtime {
|
|
|
330
336
|
if (!(response instanceof Response)) { response = new Response(response); }
|
|
331
337
|
if (!response.redirected) {
|
|
332
338
|
let location = response.headers.get('Location');
|
|
333
|
-
if (location
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
339
|
+
if (location) {
|
|
340
|
+
let xActualRedirectCode = parseInt(response.headers.get('X-Redirect-Code'));
|
|
341
|
+
if (xActualRedirectCode && response.status === this._xRedirectCode) {
|
|
342
|
+
response.attrs.status = xActualRedirectCode;
|
|
343
|
+
Observer.set(this.network, 'redirecting', location);
|
|
344
|
+
window.location = location;
|
|
345
|
+
} else if ([302,301].includes(response.status)) {
|
|
346
|
+
if (!this.isSpaRoute(location)) {
|
|
347
|
+
Observer.set(this.network, 'redirecting', location);
|
|
348
|
+
window.location = location;
|
|
349
|
+
} else {
|
|
350
|
+
this.go(location, {}, { srcType: 'rdr' });
|
|
351
|
+
}
|
|
352
|
+
}
|
|
337
353
|
}
|
|
338
354
|
}
|
|
339
355
|
return response;
|
package/test/index.test.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
|
|
1
2
|
/**
|
|
2
3
|
* @imports
|
|
3
4
|
*/
|
|
4
5
|
import { config, runtime, Context } from '../src/index.js';
|
|
5
6
|
|
|
6
7
|
let client = {
|
|
7
|
-
handle: function(httpEvent) {
|
|
8
|
+
handle: function( httpEvent ) {
|
|
8
9
|
return new httpEvent.Response({ abcd: '1234' }, {
|
|
9
10
|
status: 302,
|
|
10
11
|
headers: {
|
|
@@ -18,8 +19,8 @@ let client = {
|
|
|
18
19
|
},
|
|
19
20
|
};
|
|
20
21
|
|
|
21
|
-
const cx = Context.create({ config: config, });
|
|
22
|
-
const clientCallback = (_cx, hostName, defaultClientCallback) => client;
|
|
23
|
-
const app = await runtime.server.start.call(cx, clientCallback);
|
|
22
|
+
const cx = Context.create( { config: config, } );
|
|
23
|
+
const clientCallback = ( _cx, hostName, defaultClientCallback ) => client;
|
|
24
|
+
const app = await runtime.server.start.call( cx, clientCallback );
|
|
24
25
|
|
|
25
|
-
const response = await app.go('http://localhost/', { headers: { range: 'bytes=0-5, 6' } } );
|
|
26
|
+
const response = await app.go( 'http://localhost/', { headers: { range: 'bytes=0-5, 6' } } );
|