Intermediate commit before switching to React

feature/core
Sven Slootweg 6 years ago
parent 48073c0a0c
commit 4dd5bf7d59

@ -1,33 +1,30 @@
app
window(each="{windowItem in windows}", router="{parent.router}", window-title="{windowItem.title}", width=640, height=480, x="{windowItem.x}", y="{windowItem.y}", z=0, resizable="true", url="{windowItem.url}")
notification-box
style(type="scss").
notification-box {
position: absolute;
right: 0px;
bottom: 32px;
z-index: 2147483640;
}
script.
const stateRouter = require("../../lib/riot/state-router");
let createRouter = require("../../lib/frontend/router");
this.mixin(require("../../lib/riot/mixins/on-child"));
this.mixin(require("riot-query").mixin);
this.windows = [
{ title: "test one", x: 10, y: 10, url: "/" },
{ title: "test one", x: 10, y: 10, url: "/?target=Foo" },
{ title: "test two", x: 200, y: 200, url: "/" },
{ title: "", x: 390, y: 390, url: "/nodes/create" }
]
let currentZIndex = 0;
let router = stateRouter();
router.get("/", (req, res) => {
res.render("sample", {
text: "Hello World!"
});
});
router.get("/nodes/create", (req, res) => {
res.render("node-create");
});
this.router = router;
this.router = createRouter();
this.onChild("create:window", (window) => {
window.on("focused", () => {

@ -1,6 +1,7 @@
'use strict';
require("../window");
require("../notification-box");
require("../../views/riot/sample-view");

@ -0,0 +1,47 @@
notification-box
notification(each="{notification in notifications}", notification="{notification}")
script.
const defaultValue = require("default-value");
Object.assign(this, {
notifications: [{
title: "Foo bar!",
//message: "Bar bar baz foo. Bar.",
type: "info",
icon: "info-circle"
}, {
title: "Whoopteedoo",
//message: "Boop boop woop whoop toop boop!",
type: "error",
icon: "exclamation-circle"
}],
add: function addNotification(title, options = {}) {
let notificationObject = {
title: title,
message: options.message,
type: defaultValue(options.type, "info"),
icon: options.icon,
options: options
};
this.notifications.push(notificationObject);
if (options.timeout != null) {
setTimeout(() => {
this.remove(notificationObject);
}, options.timeout);
}
this.update();
},
remove: function removeNotification(notificationObject) {
let notificationIndex = this.notifications.indexOf(notificationObject);
// TODO: Fade/collapse animation?
if (notificationIndex !== -1) {
this.notifications.splice(notificationIndex, 1);
this.update();
}
}
})

@ -0,0 +1,5 @@
'use strict';
require("../notification");
require("./component");

@ -0,0 +1,88 @@
notification(class="type-{opts.notification.type}")
.contents
.header
button.close: i.fa.fa-times
i.icon.fa(class="fa-{opts.notification.icon}")
| { opts.notification.title }
.message(if="{opts.notification.message != null}") { opts.notification.message }
style(type="scss").
:scope {
display: block;
text-align: right;
.close {
display: none; // FIXME
float: right;
background: none;
border: 0;
padding: 1px 3px;
font-size: 12px;
color: rgb(190, 190, 190);
border: 1px solid rgb(190, 190, 190);
border-radius: 4px;
&:hover {
color: white;
border-color: white;
}
}
.contents {
text-align: left;
display: inline-block;
border-radius: 6px;
margin-right: 19px;
margin-top: 10px;
padding: 9px 14px;
color: white;
font-size: 15px;
filter: alpha(opacity=85);
opacity: 0.85;
width: auto;
background-color: black;
.header {
margin-right: 6px;
font-weight: bold;
.icon {
font-size: 19px;
margin-right: 9px !important;
}
}
.message {
margin-top: 8px;
}
}
&.type-error {
.contents {
background-color: #371B1B;
.header .icon {
color: #FFD2D2;
}
}
}
&.type-info {
.contents {
background-color: #2D2D2D;
.header .icon {
color: #CBCAFF;
}
}
}
}
/* From old code, but purpose unclear:
.notification-popup ul, .error-popup ul
{
margin: 4px 0px;
padding-left: 48px;
}
*/

@ -0,0 +1,3 @@
'use strict';
require("./component");

@ -20,7 +20,7 @@ view-manager
this.trigger("switched");
},
navigate: function(method, uri, data = {}) {
navigate: function(method, uri, data = {}, options = {}) {
return Promise.try(() => {
this.trigger("navigating");
return opts.router.handle(method, uri, data);
@ -29,6 +29,8 @@ view-manager
if (action.type === "render") {
this.switchView(action.viewName, action.locals);
}
// MARKER: Emit notifications!
});
this.trigger("navigated");
@ -47,6 +49,8 @@ view-manager
event.preventDefault();
event.stopPropagation();
return this.navigate(form.method, form.action, new FormData(form));
return this.navigate(form.method, form.action, new FormData(form), {
multipart: (form.enctype === "multipart/form-data")
});
});
});

@ -0,0 +1,55 @@
'use strict';
function isObject(value) {
return (value === Object(value));
}
function makeArrayKey(key) {
if (key.length > 2 && key.lastIndexOf('[]') === key.length - 2) {
return key
} else {
return key + '[]'
}
}
function generateKey(prefix, key) {
if (prefix == null || prefix.length === 0) {
return key;
} else {
return `${prefix}[${key}]`
}
}
module.exports = function deconstructFormObject(object, prefix) {
return Object.keys(object).reduce((items, key) => {
let value = object[key];
let newItems = [];
function transformValue(value, isInArray) {
let valueKey;
if (isInArray) {
valueKey = makeArrayKey(generateKey(prefix, key));
} else {
valueKey = generateKey(prefix, key);
}
if (Array.isArray(value)) {
value.forEach((arrayItem) => {
transformValue(arrayItem, true);
});
} else if (isObject(value)) {
newItems = newItems.concat(deconstructFormObject(value, valueKey));
} else {
newItems.push({
name: valueKey,
value: value
});
}
}
transformValue(value);
return items.concat(newItems);
}, []);
};

@ -2,6 +2,8 @@
const qs = require("qs");
// FIXME: Can this also take a URLSearchParams?
module.exports = function formDataToObject(formData) {
let items = Array.from(formData.entries()).reduce((items, [key, value]) => {
if (key.match(/\[\]$/)) {

@ -0,0 +1,36 @@
'use strict';
const Promise = require("bluebird");
const stateRouter = require("../riot/state-router");
module.exports = function createRouter() {
let router = stateRouter();
router.get("/", (req, res) => {
let text;
if (req.query.target != null) {
text = req.query.target;
} else {
text = "World";
}
res.render("sample", {
text: `Hello ${text}!`
});
});
router.get("/nodes/create", (req, res) => {
res.render("node-create");
});
router.post("/nodes/create", (req, res) => {
return Promise.try(() => {
return req.pass();
}).then((response) => {
console.log(response.body);
});
});
return router;
};

@ -0,0 +1,13 @@
'use strict';
const deconstructFormObject = require("./deconstruct-form-object");
module.exports = function objectToFormData(object) {
let formData = new FormData();
deconstructFormObject(object).forEach((item) => {
formData.append(item.name, item.value)
});
return formData;
};

@ -0,0 +1,13 @@
'use strict';
const deconstructFormObject = require("./deconstruct-form-object");
module.exports = function objectToURLSearchParams(object) {
let params = new URLSearchParams();
deconstructFormObject(object).forEach((item) => {
params.append(item.name, item.value)
});
return params;
};

Binary file not shown.

@ -3,9 +3,10 @@ const pathToRegexp = require("path-to-regexp");
const url = require("url");
const xtend = require("xtend");
const defaultValue = require("default-value");
const objectToFormData = require("object-to-formdata");
const formDataToObject = require("../formdata-to-object");
const objectToURLSearchParams = require("../object-to-urlsearchparams");
const objectToFormData = require("../object-to-formdata");
module.exports = function() {
let routes = [];
@ -38,32 +39,42 @@ module.exports = function() {
}
}
function handle(method, uri, data) {
function handle(method, uri, data, handleOptions = {}) {
return Promise.try(() => {
// FIXME: Support relative paths?
let {path, query} = url.parse(uri, true);
let route = getRoute(method, path);
let {pathname, query} = url.parse(uri, true);
let route = getRoute(method, pathname);
let tasks = [];
let body;
if (data instanceof FormData) {
body = formDataToObject(data);
} else if (data instanceof URLSearchParams) {
body = formDataToObject(data); // FIXME: Does this work?
} else {
body = data;
}
let req = {
path: path,
path: pathname,
query: query,
body: data,
body: body,
params: route.params,
pass: function(options = {}) {
return Promise.try(() => {
return window.fetch(uri, Object.assign({
let body;
if (handleOptions.multipart) {
body = objectToFormData(this.body)
} else {
body = objectToURLSearchParams(this.body);
}
return window.fetch(uri, Object.assign({ // FIXME: Override URI but maintain query?
method: method,
credentials: true,
body: objectToFormData(this.body)
body: body
}, options));
}).then((response) => {
if (!response.ok) {
@ -83,6 +94,7 @@ module.exports = function() {
// FIXME: window.fetch passthrough
},
// MARKER: passActions?
passRender: function(viewName, options = {}) {
return Promise.try(() => {
return this.pass(options.requestOptions);

@ -26,6 +26,13 @@ router.post("/autocomplete/type", (req, res) => {
})
})
router.post("/nodes/create", (req, res) => {
res.json({
result: "success",
body: req.body
});
});
router.get("/test1", (req, res) => {
res.send("test ONE <a href='/test2'>go to 2 instead</a> <a href='/test2' target='_blank'>or in a new window</a>");
});

Loading…
Cancel
Save