clapton 0.0.13 → 0.0.14
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.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/app/helpers/clapton/clapton_helper.rb +16 -1
- data/lib/clapton/engine.rb +14 -10
- data/lib/clapton/javascripts/dist/client.js +31 -19
- data/lib/clapton/javascripts/dist/components-for-test.js +439 -0
- data/lib/clapton/javascripts/dist/components.js +356 -382
- data/lib/clapton/javascripts/node_modules/diff-dom/LICENSE.txt +165 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/README.md +224 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/browser/diffDOM.js +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/browser/diffDOM.js.map +1 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/TraceLogger.d.ts +28 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/apply.d.ts +4 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/fromVirtual.d.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/index.d.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/undo.d.ts +3 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/helpers.d.ts +11 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/index.d.ts +10 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/types.d.ts +104 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/apply.d.ts +3 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/diff.d.ts +22 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/fromDOM.d.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/fromString.d.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/helpers.d.ts +40 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/index.d.ts +3 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/index.d.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.d.ts +136 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.js +1996 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.js.map +1 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.min.js +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.min.js.map +1 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/module.js +1991 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/dist/module.js.map +1 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/index.html +62 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/package.json +54 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/rollup.config.mjs +67 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/TraceLogger.ts +143 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/apply.ts +227 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/fromVirtual.ts +83 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/index.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/undo.ts +90 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/helpers.ts +40 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/index.ts +121 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/types.ts +154 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/apply.ts +349 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/diff.ts +855 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/fromDOM.ts +74 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/fromString.ts +239 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/helpers.ts +461 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/index.ts +3 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/src/index.ts +2 -0
- data/lib/clapton/javascripts/node_modules/diff-dom/tsconfig.json +103 -0
- data/lib/clapton/javascripts/rollup.config.mjs +17 -2
- data/lib/clapton/javascripts/src/actions/initialize-actions.ts +6 -3
- data/lib/clapton/javascripts/src/channel/clapton-channel.js +6 -3
- data/lib/clapton/javascripts/src/client.ts +15 -15
- data/lib/clapton/javascripts/src/components-for-test.ts +29 -0
- data/lib/clapton/javascripts/src/components.ts +4 -1
- data/lib/clapton/javascripts/src/dom/update-component.ts +3 -2
- data/lib/clapton/javascripts/src/inputs/initialize-inputs.ts +2 -2
- data/lib/clapton/test_helper/base.rb +1 -1
- data/lib/clapton/version.rb +1 -1
- metadata +49 -3
- data/lib/clapton/javascripts/src/dom/update-component.spec.ts +0 -32
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7def55e21b26dedfd8843c9ace0bf4db854abf18205de4dea7c3a203d06130f6
|
|
4
|
+
data.tar.gz: 743f8549cd8a901f2f1c76a4807f05ccace77d58e9665ad35c02626df555a08a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b05ba6c72f46212b628cee66c18e01644e285e6380862669eb7de55174338b4b9109ebf69505d398227c85f0a19a6e55580e6cf760951fad573bc13d78c73845
|
|
7
|
+
data.tar.gz: 2359db5b15a7ef59f43dc61d2bcb96609858cc0a19c996e9b18288046fe739a3d68bf5868f221c97c349af8781ff8483c979199e3c1c27914f617e8912555aba
|
data/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Clapton is a Ruby on Rails gem for building web apps with pure Ruby only (no Jav
|
|
|
12
12
|
- Action Cable (WebSocket)
|
|
13
13
|
- [Ruby2JS](https://www.ruby2js.com/) (for compiling Ruby to JavaScript)
|
|
14
14
|
- [Morphdom](https://github.com/patrick-steele-idem/morphdom)
|
|
15
|
+
- importmap
|
|
15
16
|
|
|
16
17
|
## Installation
|
|
17
18
|
|
|
@@ -2,7 +2,22 @@ module Clapton
|
|
|
2
2
|
module ClaptonHelper
|
|
3
3
|
|
|
4
4
|
def clapton_javascript_tag
|
|
5
|
-
|
|
5
|
+
all_components = Dir.glob(Rails.root.join("app", "components", "**", "*.rb"))
|
|
6
|
+
tags = <<~HTML
|
|
7
|
+
<script type="importmap">
|
|
8
|
+
{
|
|
9
|
+
"imports": {
|
|
10
|
+
"client": "/clapton/client.js",
|
|
11
|
+
"components": "/clapton/components.js",
|
|
12
|
+
#{ all_components.map do
|
|
13
|
+
|component| "\"#{File.basename(component, ".rb").camelize}\": \"/clapton/#{File.basename(component, ".rb").camelize}.js\""
|
|
14
|
+
end.join(",\n") }
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
<script type="module" src="/clapton/client.js"></script>
|
|
19
|
+
HTML
|
|
20
|
+
tags.html_safe
|
|
6
21
|
end
|
|
7
22
|
|
|
8
23
|
def clapton_tag
|
data/lib/clapton/engine.rb
CHANGED
|
@@ -32,20 +32,24 @@ module Clapton
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def compile_components
|
|
35
|
-
|
|
36
|
-
js
|
|
37
|
-
js
|
|
38
|
-
js += "\n"
|
|
39
|
-
js += "window.components = [];"
|
|
40
|
-
js += "\n"
|
|
35
|
+
FileUtils.mkdir_p(Rails.root.join("public", "clapton")) unless Rails.root.join("public", "clapton").exist?
|
|
36
|
+
File.write(Rails.root.join("public", "clapton", "components.js"), File.read(File.join(__dir__, "javascripts", "dist", "components.js")))
|
|
37
|
+
File.write(Rails.root.join("public", "clapton", "client.js"), File.read(File.join(__dir__, "javascripts", "dist", "client.js")))
|
|
41
38
|
Dir.glob(Rails.root.join("app", "components", "**", "*.rb")).each do |file|
|
|
42
|
-
|
|
39
|
+
code = File.read(file)
|
|
40
|
+
js = ""
|
|
41
|
+
js += "import { Clapton } from 'components';"
|
|
42
|
+
js += "\n"
|
|
43
|
+
code.scan(/(\w+)Component\.new/).each do |match|
|
|
44
|
+
js += "import { #{match[0]}Component } from '#{match[0]}Component';"
|
|
45
|
+
js += "\n"
|
|
46
|
+
end
|
|
47
|
+
js += Ruby2JS.convert(code, preset: true)
|
|
43
48
|
js += "\n"
|
|
44
|
-
js += "
|
|
49
|
+
js += "export { #{File.basename(file, ".rb").camelize} };"
|
|
45
50
|
js += "\n"
|
|
51
|
+
File.write(Rails.root.join("public", "clapton", "#{File.basename(file, ".rb").camelize}.js"), js)
|
|
46
52
|
end
|
|
47
|
-
FileUtils.mkdir_p(Rails.root.join("public", "clapton")) unless Rails.root.join("public", "clapton").exist?
|
|
48
|
-
File.write(Rails.root.join("public", "clapton", "index.js"), js)
|
|
49
53
|
end
|
|
50
54
|
end
|
|
51
55
|
end
|
|
@@ -1285,11 +1285,12 @@ function getConfig(name) {
|
|
|
1285
1285
|
}
|
|
1286
1286
|
}
|
|
1287
1287
|
|
|
1288
|
-
const updateComponent = (component, state, property, target) => {
|
|
1288
|
+
const updateComponent = async (component, state, property, target) => {
|
|
1289
1289
|
state[property] = target.value;
|
|
1290
1290
|
component.setAttribute("data-state", JSON.stringify(state));
|
|
1291
1291
|
const componentName = component.getAttribute("data-component");
|
|
1292
|
-
const
|
|
1292
|
+
const module = await import(`${componentName}`);
|
|
1293
|
+
const ComponentClass = module[componentName];
|
|
1293
1294
|
const instance = new ComponentClass(state, component.dataset.id);
|
|
1294
1295
|
morphdom(component, instance.render);
|
|
1295
1296
|
};
|
|
@@ -1303,8 +1304,8 @@ const initializeInputs = () => {
|
|
|
1303
1304
|
if (!attribute || !component)
|
|
1304
1305
|
return;
|
|
1305
1306
|
if (element.tagName === "INPUT") {
|
|
1306
|
-
element.addEventListener("input", (event) => {
|
|
1307
|
-
updateComponent(component, state, attribute, event.target);
|
|
1307
|
+
element.addEventListener("input", async (event) => {
|
|
1308
|
+
await updateComponent(component, state, attribute, event.target);
|
|
1308
1309
|
});
|
|
1309
1310
|
}
|
|
1310
1311
|
});
|
|
@@ -1313,14 +1314,17 @@ const initializeInputs = () => {
|
|
|
1313
1314
|
const consumer = createConsumer();
|
|
1314
1315
|
|
|
1315
1316
|
const claptonChannel = consumer.subscriptions.create("Clapton::ClaptonChannel", {
|
|
1316
|
-
connected() {
|
|
1317
|
+
connected() {
|
|
1318
|
+
window.actionCableConnected = true;
|
|
1319
|
+
},
|
|
1317
1320
|
|
|
1318
1321
|
disconnected() {},
|
|
1319
1322
|
|
|
1320
|
-
received(response) {
|
|
1323
|
+
async received(response) {
|
|
1321
1324
|
const { data, errors } = response;
|
|
1322
1325
|
const component = document.querySelector(`[data-id="${data.component.id}"]`);
|
|
1323
|
-
const
|
|
1326
|
+
const module = await import(`${data.component.name}`);
|
|
1327
|
+
const instance = new module[data.component.name](data.state, data.component.id, errors);
|
|
1324
1328
|
morphdom(component, instance.render, {
|
|
1325
1329
|
onBeforeElUpdated: (_fromEl, toEl) => {
|
|
1326
1330
|
toEl.setAttribute("data-set-event-handler", "true");
|
|
@@ -1389,9 +1393,12 @@ const initializeActionsForElement = (element) => {
|
|
|
1389
1393
|
if (!eventType || !componentName || !fnName)
|
|
1390
1394
|
return;
|
|
1391
1395
|
if (eventType === "render") {
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1396
|
+
const interval = setInterval(() => {
|
|
1397
|
+
if (window.actionCableConnected === true) {
|
|
1398
|
+
handleAction(element, stateName, fnName);
|
|
1399
|
+
clearInterval(interval);
|
|
1400
|
+
}
|
|
1401
|
+
}, 10);
|
|
1395
1402
|
element.setAttribute("data-render-event-handler", "true");
|
|
1396
1403
|
return;
|
|
1397
1404
|
}
|
|
@@ -1405,25 +1412,30 @@ const initializeActionsForElement = (element) => {
|
|
|
1405
1412
|
});
|
|
1406
1413
|
};
|
|
1407
1414
|
|
|
1408
|
-
const initializeComponents = () => {
|
|
1415
|
+
const initializeComponents = async () => {
|
|
1409
1416
|
const components = document.querySelector("#clapton")?.getAttribute("data-clapton") || "[]";
|
|
1410
|
-
JSON.parse(components)
|
|
1411
|
-
|
|
1417
|
+
const componentArray = JSON.parse(components);
|
|
1418
|
+
for (const component of componentArray) {
|
|
1419
|
+
await createAndAppendComponent(component, document.querySelector("#clapton"));
|
|
1420
|
+
}
|
|
1421
|
+
const elements = document.querySelectorAll(".clapton-component");
|
|
1422
|
+
for (const element of elements) {
|
|
1412
1423
|
const component = JSON.parse(element.getAttribute("data-clapton") || "{}");
|
|
1413
|
-
createAndAppendComponent(component, element);
|
|
1414
|
-
}
|
|
1424
|
+
await createAndAppendComponent(component, element);
|
|
1425
|
+
}
|
|
1415
1426
|
};
|
|
1416
|
-
const createAndAppendComponent = (component, element) => {
|
|
1427
|
+
const createAndAppendComponent = async (component, element) => {
|
|
1417
1428
|
const componentDom = document.createElement('div');
|
|
1418
|
-
const
|
|
1429
|
+
const module = await import(`${component.component}`);
|
|
1430
|
+
const instance = new module[component.component](component.state);
|
|
1419
1431
|
componentDom.innerHTML = instance.render;
|
|
1420
1432
|
const firstChild = componentDom.firstChild;
|
|
1421
1433
|
if (firstChild) {
|
|
1422
1434
|
element.appendChild(firstChild);
|
|
1423
1435
|
}
|
|
1424
1436
|
};
|
|
1425
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
1426
|
-
initializeComponents();
|
|
1437
|
+
document.addEventListener("DOMContentLoaded", async () => {
|
|
1438
|
+
await initializeComponents();
|
|
1427
1439
|
initializeActions();
|
|
1428
1440
|
initializeInputs();
|
|
1429
1441
|
});
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
var Clapton = (function (exports) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const htmlAttributes = (params) => {
|
|
5
|
+
const customDataAttributes = params.data || {};
|
|
6
|
+
const others = Object.keys(params).filter(key => key !== "data");
|
|
7
|
+
const flattenDataAttributes = (data, prefix = "data") => {
|
|
8
|
+
return Object.keys(data).reduce((acc, key) => {
|
|
9
|
+
const value = data[key];
|
|
10
|
+
if (typeof value === "object" && value !== null) {
|
|
11
|
+
acc.push(...flattenDataAttributes(value, `${prefix}-${key}`));
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
acc.push(`${prefix}-${key}='${escapeHtml(value)}'`);
|
|
15
|
+
}
|
|
16
|
+
return acc;
|
|
17
|
+
}, []);
|
|
18
|
+
};
|
|
19
|
+
return [
|
|
20
|
+
others.map(key => {
|
|
21
|
+
if (key === "disabled") {
|
|
22
|
+
if (params[key] === false) {
|
|
23
|
+
return "";
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
return `${key}`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return `${key}='${escapeHtml(params[key])}'`;
|
|
30
|
+
}).join(" "),
|
|
31
|
+
flattenDataAttributes(customDataAttributes).join(" ")
|
|
32
|
+
].filter(Boolean).join(" ");
|
|
33
|
+
};
|
|
34
|
+
const escapeHtml = (unsafe) => {
|
|
35
|
+
if (typeof unsafe !== "string") {
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
38
|
+
return unsafe
|
|
39
|
+
.replace(/&/g, "&")
|
|
40
|
+
.replace(/</g, "<")
|
|
41
|
+
.replace(/>/g, ">")
|
|
42
|
+
.replace(/"/g, """)
|
|
43
|
+
.replace(/'/g, "'");
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
class BlockQuote {
|
|
47
|
+
constructor(attributes = {}) {
|
|
48
|
+
this.children = [];
|
|
49
|
+
this.attributes = attributes;
|
|
50
|
+
}
|
|
51
|
+
get render() {
|
|
52
|
+
return `<blockquote ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</blockquote>`;
|
|
53
|
+
}
|
|
54
|
+
add(child) {
|
|
55
|
+
this.children.push(child);
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class Box {
|
|
61
|
+
constructor(attributes = {}) {
|
|
62
|
+
this.children = [];
|
|
63
|
+
this.attributes = attributes;
|
|
64
|
+
}
|
|
65
|
+
add(child) {
|
|
66
|
+
this.children.push(child);
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
get render() {
|
|
70
|
+
return `<div ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</div>`;
|
|
71
|
+
}
|
|
72
|
+
add_action(eventType, stateName, fnName, options = {}) {
|
|
73
|
+
this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${eventType}->${stateName}#${fnName}@${options.debounce || 0}`;
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
class Button {
|
|
79
|
+
constructor(attributes = {}) {
|
|
80
|
+
this.attributes = attributes;
|
|
81
|
+
this.children = [];
|
|
82
|
+
}
|
|
83
|
+
add(child) {
|
|
84
|
+
this.children.push(child);
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
get render() {
|
|
88
|
+
return `<button ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</button>`;
|
|
89
|
+
}
|
|
90
|
+
add_action(event, klass, fn, options = {}) {
|
|
91
|
+
this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${event}->${klass}#${fn}@${options.debounce || 0}`;
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
class Checkbox {
|
|
97
|
+
constructor(state, attribute, attributes = {}) {
|
|
98
|
+
this.state = state;
|
|
99
|
+
this.attributes = attributes;
|
|
100
|
+
this.attribute = attribute;
|
|
101
|
+
this.attributes["data-attribute"] = attribute;
|
|
102
|
+
}
|
|
103
|
+
get render() {
|
|
104
|
+
return `<input type='checkbox' ${htmlAttributes(this.attributes)} value='${this.state[this.attribute] || ""}'/>`;
|
|
105
|
+
}
|
|
106
|
+
add_action(event, klass, fn, options = {}) {
|
|
107
|
+
this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${event}->${klass}#${fn}@${options.debounce || 0}`;
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
class Code {
|
|
113
|
+
constructor(attributes = {}) {
|
|
114
|
+
this.children = [];
|
|
115
|
+
this.attributes = attributes;
|
|
116
|
+
}
|
|
117
|
+
get render() {
|
|
118
|
+
return `<code ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</code>`;
|
|
119
|
+
}
|
|
120
|
+
add(child) {
|
|
121
|
+
this.children.push(child);
|
|
122
|
+
return this;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
class DateTimeField {
|
|
127
|
+
constructor(state, attribute, attributes = {}) {
|
|
128
|
+
this.attributes = {};
|
|
129
|
+
this.state = state;
|
|
130
|
+
this.attribute = attribute;
|
|
131
|
+
this.attributes = attributes;
|
|
132
|
+
this.attributes["data-attribute"] = attribute;
|
|
133
|
+
}
|
|
134
|
+
get render() {
|
|
135
|
+
const value = this.state[this.attribute] ? this.datetime_local_value(this.state[this.attribute]) : "";
|
|
136
|
+
return `<input type='datetime-local' ${htmlAttributes(this.attributes)} value='${value}'/>`;
|
|
137
|
+
}
|
|
138
|
+
add_action(event, klass, fn, options = {}) {
|
|
139
|
+
this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${event}->${klass}#${fn}@${options.debounce || 0}`;
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
datetime_local_value(value) {
|
|
143
|
+
if (!value) {
|
|
144
|
+
return "";
|
|
145
|
+
}
|
|
146
|
+
const date = new Date(value);
|
|
147
|
+
date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
|
|
148
|
+
let month = date.getMonth() + 1;
|
|
149
|
+
let day = date.getDate();
|
|
150
|
+
let hours = date.getHours();
|
|
151
|
+
let minutes = date.getMinutes();
|
|
152
|
+
if (month < 10) {
|
|
153
|
+
month = `0${month}`;
|
|
154
|
+
}
|
|
155
|
+
if (day < 10) {
|
|
156
|
+
day = `0${day}`;
|
|
157
|
+
}
|
|
158
|
+
if (hours < 10) {
|
|
159
|
+
hours = `0${hours}`;
|
|
160
|
+
}
|
|
161
|
+
if (minutes < 10) {
|
|
162
|
+
minutes = `0${minutes}`;
|
|
163
|
+
}
|
|
164
|
+
return `${date.getFullYear()}-${month}-${day}T${hours}:${minutes}`;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
class Element {
|
|
169
|
+
constructor(type, attributes = {}) {
|
|
170
|
+
this.children = [];
|
|
171
|
+
this.type = type;
|
|
172
|
+
this.attributes = attributes;
|
|
173
|
+
}
|
|
174
|
+
get render() {
|
|
175
|
+
return `<${this.type} ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</${this.type}>`;
|
|
176
|
+
}
|
|
177
|
+
add(child) {
|
|
178
|
+
this.children.push(child);
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
class Embed {
|
|
184
|
+
constructor(html) {
|
|
185
|
+
this.html = html;
|
|
186
|
+
}
|
|
187
|
+
get render() {
|
|
188
|
+
return this.html;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
class Emphasis {
|
|
193
|
+
constructor(attributes = {}) {
|
|
194
|
+
this.children = [];
|
|
195
|
+
this.attributes = attributes;
|
|
196
|
+
}
|
|
197
|
+
get render() {
|
|
198
|
+
return `<em ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</em>`;
|
|
199
|
+
}
|
|
200
|
+
add(child) {
|
|
201
|
+
this.children.push(child);
|
|
202
|
+
return this;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
class Form {
|
|
207
|
+
constructor(attributes = {}) {
|
|
208
|
+
this.children = [];
|
|
209
|
+
this.attributes = attributes;
|
|
210
|
+
}
|
|
211
|
+
get render() {
|
|
212
|
+
return `<form ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</form>`;
|
|
213
|
+
}
|
|
214
|
+
add(child) {
|
|
215
|
+
this.children.push(child);
|
|
216
|
+
return this;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
class Heading {
|
|
221
|
+
constructor(level, attributes = {}) {
|
|
222
|
+
this.children = [];
|
|
223
|
+
this.level = level;
|
|
224
|
+
this.attributes = attributes;
|
|
225
|
+
}
|
|
226
|
+
get render() {
|
|
227
|
+
return `<h${this.level} ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</h${this.level}>`;
|
|
228
|
+
}
|
|
229
|
+
add(child) {
|
|
230
|
+
this.children.push(child);
|
|
231
|
+
return this;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
class Image {
|
|
236
|
+
constructor(src, alt, attributes = {}) {
|
|
237
|
+
this.children = [];
|
|
238
|
+
this.attributes = attributes;
|
|
239
|
+
this.src = src;
|
|
240
|
+
this.alt = alt;
|
|
241
|
+
}
|
|
242
|
+
get render() {
|
|
243
|
+
return `<img src='${this.src}' alt='${this.alt}' ${htmlAttributes(this.attributes)}/>`;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
class Link {
|
|
248
|
+
constructor(href, attributes = {}) {
|
|
249
|
+
this.children = [];
|
|
250
|
+
this.attributes = attributes;
|
|
251
|
+
this.href = href;
|
|
252
|
+
}
|
|
253
|
+
get render() {
|
|
254
|
+
return `<a href='${this.href}' ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</a>`;
|
|
255
|
+
}
|
|
256
|
+
add(child) {
|
|
257
|
+
this.children.push(child);
|
|
258
|
+
return this;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
class ListItem {
|
|
263
|
+
constructor(attributes = {}) {
|
|
264
|
+
this.children = [];
|
|
265
|
+
this.attributes = attributes;
|
|
266
|
+
}
|
|
267
|
+
add(child) {
|
|
268
|
+
this.children.push(child);
|
|
269
|
+
return this;
|
|
270
|
+
}
|
|
271
|
+
get render() {
|
|
272
|
+
return `<li ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</li>`;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
class List {
|
|
277
|
+
constructor(attributes = {}) {
|
|
278
|
+
this.children = [];
|
|
279
|
+
this.attributes = attributes;
|
|
280
|
+
}
|
|
281
|
+
add(child) {
|
|
282
|
+
this.children.push(child);
|
|
283
|
+
return this;
|
|
284
|
+
}
|
|
285
|
+
get render() {
|
|
286
|
+
return `<ul ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</ul>`;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
class OrderedList {
|
|
291
|
+
constructor(attributes = {}) {
|
|
292
|
+
this.children = [];
|
|
293
|
+
this.attributes = attributes;
|
|
294
|
+
}
|
|
295
|
+
add(child) {
|
|
296
|
+
this.children.push(child);
|
|
297
|
+
return this;
|
|
298
|
+
}
|
|
299
|
+
get render() {
|
|
300
|
+
return `<ol ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</ol>`;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
class Paragraph {
|
|
305
|
+
constructor(attributes = {}) {
|
|
306
|
+
this.children = [];
|
|
307
|
+
this.attributes = attributes;
|
|
308
|
+
}
|
|
309
|
+
get render() {
|
|
310
|
+
return `<p ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</p>`;
|
|
311
|
+
}
|
|
312
|
+
add(child) {
|
|
313
|
+
this.children.push(child);
|
|
314
|
+
return this;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
class Quote {
|
|
319
|
+
constructor(attributes = {}) {
|
|
320
|
+
this.children = [];
|
|
321
|
+
this.attributes = attributes;
|
|
322
|
+
}
|
|
323
|
+
get render() {
|
|
324
|
+
return `<q ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</q>`;
|
|
325
|
+
}
|
|
326
|
+
add(child) {
|
|
327
|
+
this.children.push(child);
|
|
328
|
+
return this;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
class RadioButton {
|
|
333
|
+
constructor(state, attribute, attributes = {}) {
|
|
334
|
+
this.state = state;
|
|
335
|
+
this.attributes = attributes;
|
|
336
|
+
this.attribute = attribute;
|
|
337
|
+
this.attributes["data-attribute"] = attribute;
|
|
338
|
+
}
|
|
339
|
+
get render() {
|
|
340
|
+
return `<input type='radio' ${htmlAttributes(this.attributes)} value='${this.state[this.attribute] || ""}'/>`;
|
|
341
|
+
}
|
|
342
|
+
add_action(event, klass, fn, options = {}) {
|
|
343
|
+
this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${event}->${klass}#${fn}@${options.debounce || 0}`;
|
|
344
|
+
return this;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
class Select {
|
|
349
|
+
constructor(options = [], state, attribute, attributes = {}) {
|
|
350
|
+
this.children = [];
|
|
351
|
+
this.options = options;
|
|
352
|
+
this.state = state;
|
|
353
|
+
this.attribute = attribute;
|
|
354
|
+
this.attributes = attributes;
|
|
355
|
+
}
|
|
356
|
+
get render() {
|
|
357
|
+
return `<select ${htmlAttributes(this.attributes)}>${this.options.map(option => `<option value='${option.value}'${option.value === this.state[this.attribute] ? " selected" : ""}>${option.text}</option>`).join("")}${this.children.map(child => child.render).join("")}</select>`;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
class Span {
|
|
362
|
+
constructor(attributes = {}) {
|
|
363
|
+
this.children = [];
|
|
364
|
+
this.attributes = attributes;
|
|
365
|
+
}
|
|
366
|
+
get render() {
|
|
367
|
+
return `<span ${htmlAttributes(this.attributes)}>${this.children.map(child => child.render).join("")}</span>`;
|
|
368
|
+
}
|
|
369
|
+
add(child) {
|
|
370
|
+
this.children.push(child);
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
class Component {
|
|
376
|
+
constructor(state = {}, id = Math.random().toString(36).substring(2, 10), errors = []) {
|
|
377
|
+
this._state = state;
|
|
378
|
+
this.id = id;
|
|
379
|
+
this._errors = errors;
|
|
380
|
+
this._root = new Box({ data: { component: this.constructor.name, state: JSON.stringify(this._state), id: this.id, errors: this._errors } });
|
|
381
|
+
}
|
|
382
|
+
get render() {
|
|
383
|
+
return this._root.render;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
class TextField {
|
|
388
|
+
constructor(state, attribute, attributes = {}) {
|
|
389
|
+
this.state = state;
|
|
390
|
+
this.attributes = attributes;
|
|
391
|
+
this.attribute = attribute;
|
|
392
|
+
this.attributes["data-attribute"] = attribute;
|
|
393
|
+
}
|
|
394
|
+
get render() {
|
|
395
|
+
return `<input type='text' ${htmlAttributes(this.attributes)} value='${this.state[this.attribute] || ""}'/>`;
|
|
396
|
+
}
|
|
397
|
+
add_action(event, klass, fn, options = {}) {
|
|
398
|
+
this.attributes["data-action"] = `${this.attributes["data-action"] || ""} ${event}->${klass}#${fn}@${options.debounce || 0}`;
|
|
399
|
+
return this;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
class Text {
|
|
404
|
+
constructor(value) {
|
|
405
|
+
this.value = value;
|
|
406
|
+
}
|
|
407
|
+
get render() {
|
|
408
|
+
return this.value;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
exports.BlockQuote = BlockQuote;
|
|
413
|
+
exports.Box = Box;
|
|
414
|
+
exports.Button = Button;
|
|
415
|
+
exports.Checkbox = Checkbox;
|
|
416
|
+
exports.Code = Code;
|
|
417
|
+
exports.Component = Component;
|
|
418
|
+
exports.DateTimeField = DateTimeField;
|
|
419
|
+
exports.Element = Element;
|
|
420
|
+
exports.Embed = Embed;
|
|
421
|
+
exports.Emphasis = Emphasis;
|
|
422
|
+
exports.Form = Form;
|
|
423
|
+
exports.Heading = Heading;
|
|
424
|
+
exports.Image = Image;
|
|
425
|
+
exports.Link = Link;
|
|
426
|
+
exports.List = List;
|
|
427
|
+
exports.ListItem = ListItem;
|
|
428
|
+
exports.OrderedList = OrderedList;
|
|
429
|
+
exports.Paragraph = Paragraph;
|
|
430
|
+
exports.Quote = Quote;
|
|
431
|
+
exports.RadioButton = RadioButton;
|
|
432
|
+
exports.Select = Select;
|
|
433
|
+
exports.Span = Span;
|
|
434
|
+
exports.Text = Text;
|
|
435
|
+
exports.TextField = TextField;
|
|
436
|
+
|
|
437
|
+
return exports;
|
|
438
|
+
|
|
439
|
+
})({});
|