@caboodle-tech/node-simple-server 4.2.4 → 4.3.0
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 +49 -38
- package/bin/nss.js +101 -68
- package/bin/print.js +0 -2
- package/changelogs/v4.md +36 -0
- package/eslint/html-rules.js +24 -0
- package/eslint/js-rules.js +143 -0
- package/eslint/json-rules.js +21 -0
- package/eslint.config.js +44 -0
- package/examples/controllers/prod-website.js +2 -3
- package/examples/controllers/website.js +2 -3
- package/examples/controllers/websocket.js +4 -10
- package/examples/www-production/js/main.js +2 -3
- package/examples/www-website/character-test.html +252 -0
- package/examples/www-website/index.html +4 -1
- package/examples/www-website/js/main.js +2 -3
- package/examples/www-websockets/js/main.js +9 -7
- package/handlers/dir-listing.html +9 -9
- package/handlers/forbidden.html +5 -5
- package/handlers/live-reloading.html +1 -1
- package/handlers/not-found.html +5 -5
- package/handlers/websocket-only.html +1 -1
- package/package.json +11 -6
- package/.eslintrc.json +0 -50
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caboodle Tech's opinionated rules for linting JavaScript with ESLint. Feel free to adapt or
|
|
3
|
+
* modify these rules to suit your needs.
|
|
4
|
+
*
|
|
5
|
+
* ESLint Rules: {@link https://eslint.org/docs/latest/rules/ ESLint Docs}
|
|
6
|
+
*/
|
|
7
|
+
export default {
|
|
8
|
+
'class-methods-use-this': 'off',
|
|
9
|
+
'comma-dangle': ['error', 'never'],
|
|
10
|
+
'default-case': 'off',
|
|
11
|
+
indent: [
|
|
12
|
+
'error',
|
|
13
|
+
4,
|
|
14
|
+
{
|
|
15
|
+
SwitchCase: 1
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
'max-len': ['warn', 120],
|
|
19
|
+
'no-continue': 'warn',
|
|
20
|
+
'no-param-reassign': 'warn',
|
|
21
|
+
'no-plusplus': [
|
|
22
|
+
'error',
|
|
23
|
+
{
|
|
24
|
+
allowForLoopAfterthoughts: true
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
'no-restricted-syntax': 'off',
|
|
28
|
+
'no-use-before-define': 'off',
|
|
29
|
+
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
30
|
+
'object-curly-spacing': ['error', 'always'],
|
|
31
|
+
'padded-blocks': [
|
|
32
|
+
'error',
|
|
33
|
+
{
|
|
34
|
+
classes: 'always'
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
'arrow-body-style': ['error', 'always'],
|
|
38
|
+
'arrow-parens': ['error', 'always'],
|
|
39
|
+
'arrow-spacing': ['error', { before: true, after: true }],
|
|
40
|
+
'block-spacing': ['error', 'always'],
|
|
41
|
+
'brace-style': ['error', '1tbs', { allowSingleLine: true }],
|
|
42
|
+
'comma-spacing': ['error', { before: false, after: true }],
|
|
43
|
+
'computed-property-spacing': ['error', 'never'],
|
|
44
|
+
'dot-location': ['error', 'property'],
|
|
45
|
+
'dot-notation': ['error', { allowKeywords: true }],
|
|
46
|
+
'eol-last': ['error', 'always'],
|
|
47
|
+
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
|
48
|
+
'func-call-spacing': ['error', 'never'],
|
|
49
|
+
'func-name-matching': 'error',
|
|
50
|
+
'func-names': ['error', 'always'],
|
|
51
|
+
'func-style': [
|
|
52
|
+
'error',
|
|
53
|
+
'declaration',
|
|
54
|
+
{ allowArrowFunctions: true }
|
|
55
|
+
],
|
|
56
|
+
'generator-star-spacing': ['error', { before: true, after: true }],
|
|
57
|
+
'key-spacing': ['error', { beforeColon: false, afterColon: true }],
|
|
58
|
+
'keyword-spacing': ['error', { before: true, after: true }],
|
|
59
|
+
'lines-between-class-members': [
|
|
60
|
+
'error',
|
|
61
|
+
'always',
|
|
62
|
+
{ exceptAfterSingleLine: true }
|
|
63
|
+
],
|
|
64
|
+
'newline-per-chained-call': ['error', { ignoreChainWithDepth: 4 }],
|
|
65
|
+
'no-confusing-arrow': ['error', { allowParens: true }],
|
|
66
|
+
'no-dupe-class-members': 'error',
|
|
67
|
+
'no-duplicate-imports': 'error',
|
|
68
|
+
'no-else-return': ['error', { allowElseIf: false }],
|
|
69
|
+
'no-eval': 'error',
|
|
70
|
+
'no-extra-parens': [
|
|
71
|
+
'error',
|
|
72
|
+
'all',
|
|
73
|
+
{ nestedBinaryExpressions: false }
|
|
74
|
+
],
|
|
75
|
+
'no-floating-decimal': 'error',
|
|
76
|
+
'no-lonely-if': 'error',
|
|
77
|
+
'no-mixed-operators': 'error',
|
|
78
|
+
'no-multi-assign': 'error',
|
|
79
|
+
'no-multiple-empty-lines': [
|
|
80
|
+
'error',
|
|
81
|
+
{ max: 1, maxEOF: 0, maxBOF: 0 }
|
|
82
|
+
],
|
|
83
|
+
'no-return-await': 'error',
|
|
84
|
+
'no-self-compare': 'error',
|
|
85
|
+
'no-trailing-spaces': 'error',
|
|
86
|
+
'no-unneeded-ternary': 'error',
|
|
87
|
+
'no-useless-concat': 'error',
|
|
88
|
+
'no-var': 'error',
|
|
89
|
+
'object-curly-newline': ['error', { consistent: true }],
|
|
90
|
+
'object-curly-spacing': ['error', 'always'],
|
|
91
|
+
'object-shorthand': [
|
|
92
|
+
'error',
|
|
93
|
+
'always',
|
|
94
|
+
{ ignoreConstructors: false, avoidQuotes: true }
|
|
95
|
+
],
|
|
96
|
+
'one-var': ['error', 'never'],
|
|
97
|
+
'one-var-declaration-per-line': ['error', 'always'],
|
|
98
|
+
'operator-assignment': ['error', 'always'],
|
|
99
|
+
'operator-linebreak': ['error', 'after'],
|
|
100
|
+
'prefer-arrow-callback': 'error',
|
|
101
|
+
'prefer-const': 'error',
|
|
102
|
+
'prefer-destructuring': [
|
|
103
|
+
'error',
|
|
104
|
+
{
|
|
105
|
+
VariableDeclarator: { array: false, object: true },
|
|
106
|
+
AssignmentExpression: { array: true, object: true }
|
|
107
|
+
}
|
|
108
|
+
],
|
|
109
|
+
'prefer-numeric-literals': 'error',
|
|
110
|
+
'prefer-template': 'error',
|
|
111
|
+
'quote-props': ['error', 'as-needed'],
|
|
112
|
+
quotes: [
|
|
113
|
+
'error',
|
|
114
|
+
'single',
|
|
115
|
+
{ avoidEscape: true, allowTemplateLiterals: true }
|
|
116
|
+
],
|
|
117
|
+
'require-await': 'off',
|
|
118
|
+
'rest-spread-spacing': ['error', 'never'],
|
|
119
|
+
semi: ['error', 'always'],
|
|
120
|
+
'semi-spacing': ['error', { before: false, after: true }],
|
|
121
|
+
'semi-style': ['error', 'last'],
|
|
122
|
+
'space-before-blocks': 'error',
|
|
123
|
+
'space-before-function-paren': ['error', 'never'],
|
|
124
|
+
'space-in-parens': ['error', 'never'],
|
|
125
|
+
'space-infix-ops': 'error',
|
|
126
|
+
'space-unary-ops': ['error', { words: true, nonwords: false }],
|
|
127
|
+
'spaced-comment': [
|
|
128
|
+
'error',
|
|
129
|
+
'always',
|
|
130
|
+
{
|
|
131
|
+
line: { markers: ['/'] },
|
|
132
|
+
block: {
|
|
133
|
+
balanced: true,
|
|
134
|
+
markers: ['*'],
|
|
135
|
+
exceptions: ['*']
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
'template-curly-spacing': ['error', 'never'],
|
|
140
|
+
'template-tag-spacing': ['error', 'never'],
|
|
141
|
+
yoda: ['error', 'never', { exceptRange: true }]
|
|
142
|
+
};
|
|
143
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caboodle Tech's opinionated rules for linting JSON with ESLint. Feel free to adapt or modify
|
|
3
|
+
* these rules to suit your needs.
|
|
4
|
+
*
|
|
5
|
+
* ESLint Plugin: {@link https://www.npmjs.com/package/eslint-plugin-jsonc eslint-plugin-jsonc}
|
|
6
|
+
* JSON ESLint Parser: {@link https://www.npmjs.com/package/jsonc-eslint-parser jsonc-eslint-parser}
|
|
7
|
+
* JSON ESLint Rules: {@link https://ota-meshi.github.io/eslint-plugin-jsonc/rules/ JSON ESLint Docs}
|
|
8
|
+
*/
|
|
9
|
+
export default {
|
|
10
|
+
'jsonc/array-bracket-spacing': ['error', 'never'],
|
|
11
|
+
'jsonc/comma-dangle': ['error', 'never'],
|
|
12
|
+
'jsonc/comma-style': ['error', 'last'],
|
|
13
|
+
'jsonc/indent': ['error', 4],
|
|
14
|
+
'jsonc/key-spacing': ['error', { beforeColon: false, afterColon: true }],
|
|
15
|
+
'jsonc/object-curly-newline': ['error', { consistent: true }],
|
|
16
|
+
'jsonc/object-curly-spacing': ['error', 'always'],
|
|
17
|
+
'jsonc/object-property-newline': ['error', { allowMultiplePropertiesPerLine: true }],
|
|
18
|
+
'jsonc/quote-props': ['error', 'always'],
|
|
19
|
+
'jsonc/quotes': ['error', 'double']
|
|
20
|
+
};
|
|
21
|
+
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import HtmlParser from '@html-eslint/parser';
|
|
2
|
+
import HtmlPlugin from '@html-eslint/eslint-plugin';
|
|
3
|
+
import HtmlRules from './eslint/html-rules.js';
|
|
4
|
+
import JsRules from './eslint/js-rules.js';
|
|
5
|
+
import JsonRules from './eslint/json-rules.js';
|
|
6
|
+
import JsoncParser from 'jsonc-eslint-parser';
|
|
7
|
+
import JsoncPlugin from 'eslint-plugin-jsonc';
|
|
8
|
+
|
|
9
|
+
export default [
|
|
10
|
+
{
|
|
11
|
+
// Caboodle Tech HTML settings.
|
|
12
|
+
...HtmlPlugin.configs['flat/recommended'],
|
|
13
|
+
files: ['**/*.html'],
|
|
14
|
+
plugins: {
|
|
15
|
+
'@html-eslint': HtmlPlugin
|
|
16
|
+
},
|
|
17
|
+
rules: { ...HtmlRules },
|
|
18
|
+
languageOptions: {
|
|
19
|
+
parser: HtmlParser
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
// Caboodle Tech JavaScript settings.
|
|
24
|
+
files: ['**/*.js'],
|
|
25
|
+
languageOptions: {
|
|
26
|
+
ecmaVersion: 'latest',
|
|
27
|
+
sourceType: 'module'
|
|
28
|
+
},
|
|
29
|
+
rules: { ...JsRules }
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
// Caboodle Tech JSON settings.
|
|
33
|
+
files: ['**/*.json'],
|
|
34
|
+
languageOptions: {
|
|
35
|
+
parser: JsoncParser,
|
|
36
|
+
ecmaVersion: 'latest'
|
|
37
|
+
},
|
|
38
|
+
plugins: {
|
|
39
|
+
jsonc: JsoncPlugin
|
|
40
|
+
},
|
|
41
|
+
rules: { ...JsonRules }
|
|
42
|
+
}
|
|
43
|
+
];
|
|
44
|
+
|
|
@@ -25,8 +25,7 @@ const WebsiteDemo = () => {
|
|
|
25
25
|
// Start the server.
|
|
26
26
|
server.start();
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
function callback(event, path, ext) {
|
|
28
|
+
const callback = (event, path, ext) => {
|
|
30
29
|
console.log(event, path, ext);
|
|
31
30
|
if (ext === 'css') {
|
|
32
31
|
server.reloadAllStyles();
|
|
@@ -39,7 +38,7 @@ const WebsiteDemo = () => {
|
|
|
39
38
|
if (event === 'change') {
|
|
40
39
|
server.reloadSinglePage(path);
|
|
41
40
|
}
|
|
42
|
-
}
|
|
41
|
+
};
|
|
43
42
|
|
|
44
43
|
// Build a bare minimum watcher options object.
|
|
45
44
|
const watcherOptions = {
|
|
@@ -23,8 +23,7 @@ const WebsiteDemo = () => {
|
|
|
23
23
|
// Start the server.
|
|
24
24
|
server.start();
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
function callback(event, path, ext) {
|
|
26
|
+
const callback = (event, path, ext) => {
|
|
28
27
|
console.log(event, path, ext);
|
|
29
28
|
if (ext === 'css') {
|
|
30
29
|
server.reloadAllStyles();
|
|
@@ -37,7 +36,7 @@ const WebsiteDemo = () => {
|
|
|
37
36
|
if (event === 'change') {
|
|
38
37
|
server.reloadSinglePage(path);
|
|
39
38
|
}
|
|
40
|
-
}
|
|
39
|
+
};
|
|
41
40
|
|
|
42
41
|
// Build a bare minimum watcher options object.
|
|
43
42
|
const watcherOptions = {
|
|
@@ -23,8 +23,7 @@ const WebsocketDemo = () => {
|
|
|
23
23
|
// Start the server.
|
|
24
24
|
server.start();
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
function callback(event, path, ext) {
|
|
26
|
+
const callback = (event, path, ext) => {
|
|
28
27
|
if (ext === 'css') {
|
|
29
28
|
server.reloadAllStyles();
|
|
30
29
|
return;
|
|
@@ -36,7 +35,7 @@ const WebsocketDemo = () => {
|
|
|
36
35
|
if (event === 'change') {
|
|
37
36
|
server.reloadSinglePage(path);
|
|
38
37
|
}
|
|
39
|
-
}
|
|
38
|
+
};
|
|
40
39
|
|
|
41
40
|
// Build a bare minimum watcher options object.
|
|
42
41
|
const watcherOptions = {
|
|
@@ -58,21 +57,16 @@ const WebsocketDemo = () => {
|
|
|
58
57
|
// Keep a reply count so we can distinguish replies.
|
|
59
58
|
const replyCount = {};
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
function websocketHandler(message, pageId) {
|
|
63
|
-
// Our demo only sends stings so ignore anything else.
|
|
60
|
+
const websocketHandler = (message, pageId) => {
|
|
64
61
|
if (message.type === 'string') {
|
|
65
|
-
// We record reply counts by page so make sure we have a record for this page.
|
|
66
62
|
if (!replyCount[pageId]) { replyCount[pageId] = 0; }
|
|
67
|
-
// Display the users message in the servers (NSS's) terminal.
|
|
68
63
|
console.log(`[websocket:${pageId}] Message from frontend --> ${message.message}`);
|
|
69
|
-
// To demonstrate we can reply send a message back after a delay.
|
|
70
64
|
setTimeout(() => {
|
|
71
65
|
replyCount[pageId] += 1;
|
|
72
66
|
server.message(pageId, `Reply ${replyCount[pageId]} from backend to page with id: ${pageId}`);
|
|
73
67
|
}, 2000);
|
|
74
68
|
}
|
|
75
|
-
}
|
|
69
|
+
};
|
|
76
70
|
|
|
77
71
|
// Register our websocket handler to respond to only index pages.
|
|
78
72
|
server.addWebsocketCallback('index.html', websocketHandler);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const loadFoxImage = () => {
|
|
3
2
|
const container = document.getElementById('fox-container');
|
|
4
3
|
if (!container) {
|
|
5
4
|
console.log('DEMO: Could not locate the image container for the fox image.');
|
|
@@ -23,7 +22,7 @@ function loadFoxImage() {
|
|
|
23
22
|
.catch((_) => {
|
|
24
23
|
console.log('DEMO: There was an error trying to load the fox image.');
|
|
25
24
|
});
|
|
26
|
-
}
|
|
25
|
+
};
|
|
27
26
|
|
|
28
27
|
document.addEventListener('DOMContentLoaded', () => {
|
|
29
28
|
console.log('DEMO: Loading a random image of a fox in 3 seconds...');
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Character Test Page</title>
|
|
7
|
+
<link rel="stylesheet" href="./css/normalize.css">
|
|
8
|
+
<link rel="stylesheet" href="./css/main.css">
|
|
9
|
+
<style>
|
|
10
|
+
.edge-section { margin: 2rem 0; }
|
|
11
|
+
.edge-section h2 { font-size: 1.8rem; margin-bottom: 0.75rem; border-bottom: 1px solid #ccc; }
|
|
12
|
+
.edge-section table { border-collapse: collapse; width: 100%; max-width: 640px; }
|
|
13
|
+
.edge-section th, .edge-section td { border: 1px solid #ccc; padding: 0.5rem 0.75rem; text-align: left; }
|
|
14
|
+
.edge-section th { background: #f5f5f5; }
|
|
15
|
+
.rtl-block { direction: rtl; text-align: right; }
|
|
16
|
+
.ltr-block { direction: ltr; text-align: left; }
|
|
17
|
+
.mixed-rtl-ltr { unicode-bidi: bidi-override; }
|
|
18
|
+
.back-link { display: inline-block; margin-bottom: 1rem; }
|
|
19
|
+
</style>
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<div id="page-container">
|
|
23
|
+
<main>
|
|
24
|
+
<div class="content">
|
|
25
|
+
<a class="back-link" href="./index.html">← Back to Website Demo</a>
|
|
26
|
+
<h1>Character Test Page</h1>
|
|
27
|
+
<p>
|
|
28
|
+
This page tests that the server and browser handle UTF-8 correctly: HTML entities,
|
|
29
|
+
emojis, RTL/LTR text, and mixed scripts.
|
|
30
|
+
</p>
|
|
31
|
+
|
|
32
|
+
<section class="edge-section" id="entities">
|
|
33
|
+
<h2>HTML Entities (Table)</h2>
|
|
34
|
+
<p>Rendered via reference: character from entity, decimal, or hex. Rendered via literal: character typed directly in the source (UTF-8).</p>
|
|
35
|
+
<table>
|
|
36
|
+
<thead>
|
|
37
|
+
<tr>
|
|
38
|
+
<th>Name</th>
|
|
39
|
+
<th>Entity</th>
|
|
40
|
+
<th>Decimal</th>
|
|
41
|
+
<th>Hex</th>
|
|
42
|
+
<th>Via Reference</th>
|
|
43
|
+
<th>Via Literal</th>
|
|
44
|
+
</tr>
|
|
45
|
+
</thead>
|
|
46
|
+
<tbody>
|
|
47
|
+
<tr>
|
|
48
|
+
<td>Ampersand</td>
|
|
49
|
+
<td><code>&amp;</code></td>
|
|
50
|
+
<td><code>&#38;</code></td>
|
|
51
|
+
<td><code>&#x26;</code></td>
|
|
52
|
+
<td>&</td>
|
|
53
|
+
<td>n/a</td>
|
|
54
|
+
</tr>
|
|
55
|
+
<tr>
|
|
56
|
+
<td>Less than</td>
|
|
57
|
+
<td><code>&lt;</code></td>
|
|
58
|
+
<td><code>&#60;</code></td>
|
|
59
|
+
<td><code>&#x3C;</code></td>
|
|
60
|
+
<td><</td>
|
|
61
|
+
<td>n/a</td>
|
|
62
|
+
</tr>
|
|
63
|
+
<tr>
|
|
64
|
+
<td>Greater than</td>
|
|
65
|
+
<td><code>&gt;</code></td>
|
|
66
|
+
<td><code>&#62;</code></td>
|
|
67
|
+
<td><code>&#x3E;</code></td>
|
|
68
|
+
<td>></td>
|
|
69
|
+
<td>n/a</td>
|
|
70
|
+
</tr>
|
|
71
|
+
<tr>
|
|
72
|
+
<td>Double quote</td>
|
|
73
|
+
<td><code>&quot;</code></td>
|
|
74
|
+
<td><code>&#34;</code></td>
|
|
75
|
+
<td><code>&#x22;</code></td>
|
|
76
|
+
<td>"</td>
|
|
77
|
+
<td>"</td>
|
|
78
|
+
</tr>
|
|
79
|
+
<tr>
|
|
80
|
+
<td>Apostrophe</td>
|
|
81
|
+
<td><code>&apos;</code></td>
|
|
82
|
+
<td><code>&#39;</code></td>
|
|
83
|
+
<td><code>&#x27;</code></td>
|
|
84
|
+
<td>'</td>
|
|
85
|
+
<td>'</td>
|
|
86
|
+
</tr>
|
|
87
|
+
<tr>
|
|
88
|
+
<td>Non-breaking space</td>
|
|
89
|
+
<td><code>&nbsp;</code></td>
|
|
90
|
+
<td><code>&#160;</code></td>
|
|
91
|
+
<td><code>&#xA0;</code></td>
|
|
92
|
+
<td>[ ]</td>
|
|
93
|
+
<td>[ ]</td>
|
|
94
|
+
</tr>
|
|
95
|
+
<tr>
|
|
96
|
+
<td>Copyright</td>
|
|
97
|
+
<td><code>&copy;</code></td>
|
|
98
|
+
<td><code>&#169;</code></td>
|
|
99
|
+
<td><code>&#xA9;</code></td>
|
|
100
|
+
<td>©</td>
|
|
101
|
+
<td>©</td>
|
|
102
|
+
</tr>
|
|
103
|
+
<tr>
|
|
104
|
+
<td>En dash</td>
|
|
105
|
+
<td><code>&ndash;</code></td>
|
|
106
|
+
<td><code>&#8211;</code></td>
|
|
107
|
+
<td><code>&#x2013;</code></td>
|
|
108
|
+
<td>–</td>
|
|
109
|
+
<td>–</td>
|
|
110
|
+
</tr>
|
|
111
|
+
<tr>
|
|
112
|
+
<td>Em dash</td>
|
|
113
|
+
<td><code>&mdash;</code></td>
|
|
114
|
+
<td><code>&#8212;</code></td>
|
|
115
|
+
<td><code>&#x2014;</code></td>
|
|
116
|
+
<td>—</td>
|
|
117
|
+
<td>—</td>
|
|
118
|
+
</tr>
|
|
119
|
+
</tbody>
|
|
120
|
+
</table>
|
|
121
|
+
</section>
|
|
122
|
+
|
|
123
|
+
<section class="edge-section" id="emojis">
|
|
124
|
+
<h2>Emojis & Symbols (Unicode)</h2>
|
|
125
|
+
<p>Via reference: numeric character reference (e.g. 😀). Via literal: character typed in source (UTF-8). Both render as Unicode.</p>
|
|
126
|
+
<table>
|
|
127
|
+
<thead>
|
|
128
|
+
<tr>
|
|
129
|
+
<th>Name</th>
|
|
130
|
+
<th>Unicode</th>
|
|
131
|
+
<th>Via Reference</th>
|
|
132
|
+
<th>Via Literal</th>
|
|
133
|
+
</tr>
|
|
134
|
+
</thead>
|
|
135
|
+
<tbody>
|
|
136
|
+
<tr>
|
|
137
|
+
<td>Grinning face</td>
|
|
138
|
+
<td><code>U+1F600</code></td>
|
|
139
|
+
<td>😀</td>
|
|
140
|
+
<td>😀</td>
|
|
141
|
+
</tr>
|
|
142
|
+
<tr>
|
|
143
|
+
<td>Party popper</td>
|
|
144
|
+
<td><code>U+1F389</code></td>
|
|
145
|
+
<td>🎉</td>
|
|
146
|
+
<td>🎉</td>
|
|
147
|
+
</tr>
|
|
148
|
+
<tr>
|
|
149
|
+
<td>Red heart</td>
|
|
150
|
+
<td><code>U+2764</code></td>
|
|
151
|
+
<td>❤</td>
|
|
152
|
+
<td>❤</td>
|
|
153
|
+
</tr>
|
|
154
|
+
<tr>
|
|
155
|
+
<td>Light bulb</td>
|
|
156
|
+
<td><code>U+1F4A1</code></td>
|
|
157
|
+
<td>💡</td>
|
|
158
|
+
<td>💡</td>
|
|
159
|
+
</tr>
|
|
160
|
+
<tr>
|
|
161
|
+
<td>Check mark</td>
|
|
162
|
+
<td><code>U+2714</code></td>
|
|
163
|
+
<td>✔</td>
|
|
164
|
+
<td>✔</td>
|
|
165
|
+
</tr>
|
|
166
|
+
<tr>
|
|
167
|
+
<td>Cross mark</td>
|
|
168
|
+
<td><code>U+274C</code></td>
|
|
169
|
+
<td>❌</td>
|
|
170
|
+
<td>❌</td>
|
|
171
|
+
</tr>
|
|
172
|
+
<tr>
|
|
173
|
+
<td>Star</td>
|
|
174
|
+
<td><code>U+2B50</code></td>
|
|
175
|
+
<td>⭐</td>
|
|
176
|
+
<td>⭐</td>
|
|
177
|
+
</tr>
|
|
178
|
+
<tr>
|
|
179
|
+
<td>Flag (United States)</td>
|
|
180
|
+
<td><code>U+1F1FA U+1F1F8</code></td>
|
|
181
|
+
<td>🇺🇸</td>
|
|
182
|
+
<td>🇺🇸</td>
|
|
183
|
+
</tr>
|
|
184
|
+
<tr>
|
|
185
|
+
<td>Flag (United Kingdom)</td>
|
|
186
|
+
<td><code>U+1F1EC U+1F1E7</code></td>
|
|
187
|
+
<td>🇬🇧</td>
|
|
188
|
+
<td>🇬🇧</td>
|
|
189
|
+
</tr>
|
|
190
|
+
<tr>
|
|
191
|
+
<td>Flag (Canada)</td>
|
|
192
|
+
<td><code>U+1F1E8 U+1F1E6</code></td>
|
|
193
|
+
<td>🇨🇦</td>
|
|
194
|
+
<td>🇨🇦</td>
|
|
195
|
+
</tr>
|
|
196
|
+
<tr>
|
|
197
|
+
<td>Flag (Japan)</td>
|
|
198
|
+
<td><code>U+1F1EF U+1F1F5</code></td>
|
|
199
|
+
<td>🇯🇵</td>
|
|
200
|
+
<td>🇯🇵</td>
|
|
201
|
+
</tr>
|
|
202
|
+
<tr>
|
|
203
|
+
<td>Flag (France)</td>
|
|
204
|
+
<td><code>U+1F1EB U+1F1F7</code></td>
|
|
205
|
+
<td>🇫🇷</td>
|
|
206
|
+
<td>🇫🇷</td>
|
|
207
|
+
</tr>
|
|
208
|
+
<tr>
|
|
209
|
+
<td>Flag (Australia)</td>
|
|
210
|
+
<td><code>U+1F1E6 U+1F1FA</code></td>
|
|
211
|
+
<td>🇦🇺</td>
|
|
212
|
+
<td>🇦🇺</td>
|
|
213
|
+
</tr>
|
|
214
|
+
</tbody>
|
|
215
|
+
</table>
|
|
216
|
+
</section>
|
|
217
|
+
|
|
218
|
+
<section class="edge-section" id="arabic">
|
|
219
|
+
<h2>Arabic (RTL)</h2>
|
|
220
|
+
<p class="rtl-block" dir="rtl" lang="ar">
|
|
221
|
+
النص العربي للاختبار. إذا ظهر هذا النص بشكل صحيح ومن اليمين إلى اليسار، فإن الترميز واتجاه النص يعملان بشكل سليم.
|
|
222
|
+
</p>
|
|
223
|
+
<p><em>Above: Arabic sample. Direction should be right-to-left.</em></p>
|
|
224
|
+
</section>
|
|
225
|
+
|
|
226
|
+
<section class="edge-section" id="mandarin">
|
|
227
|
+
<h2>Mandarin / Chinese</h2>
|
|
228
|
+
<p class="ltr-block" lang="zh">
|
|
229
|
+
这是中文测试。简体字与繁体字:简体 = 简体字,繁体 = 繁體字。如果这些字符显示正确,说明 UTF-8 编码正常。
|
|
230
|
+
</p>
|
|
231
|
+
<p><em>Above: Mandarin (Simplified and Traditional). Direction LTR.</em></p>
|
|
232
|
+
</section>
|
|
233
|
+
|
|
234
|
+
<section class="edge-section" id="mixed">
|
|
235
|
+
<h2>Mixed RTL and LTR</h2>
|
|
236
|
+
<p>
|
|
237
|
+
English sentence with <span dir="rtl" lang="ar">كلمة عربية</span> in the middle, then more English.
|
|
238
|
+
</p>
|
|
239
|
+
<p dir="rtl">
|
|
240
|
+
جملة عربية <span dir="ltr" lang="en">with English in the middle</span> ثم تكملة عربية.
|
|
241
|
+
</p>
|
|
242
|
+
</section>
|
|
243
|
+
|
|
244
|
+
<section class="edge-section" id="raw-unicode">
|
|
245
|
+
<h2>Raw Unicode in Page (No Entities)</h2>
|
|
246
|
+
<p>Emoji in source: 😀 🎉 中文 العربية</p>
|
|
247
|
+
</section>
|
|
248
|
+
</div>
|
|
249
|
+
</main>
|
|
250
|
+
</div>
|
|
251
|
+
</body>
|
|
252
|
+
</html>
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
<div class="content">
|
|
20
20
|
<h1>Website Demo</h1>
|
|
21
21
|
<p>
|
|
22
|
-
This is a simple demo of using Node Simple Server (NSS) for static website (HTML, CSS, JS) development. Try editing the example files for this site and watch how the page auto reloads your changes. You can also open the developer console to see helpful messages being printed by the demo.
|
|
22
|
+
This is a simple demo of using Node Simple Server (NSS) for static website (HTML, CSS, JS) development. Try editing the example files for this site and watch how the page auto reloads your changes. You can also open the developer console to see helpful messages being printed by the demo. You should also view your terminal to see the messages being printed by the demo.
|
|
23
23
|
</p>
|
|
24
24
|
<div id="fox-container">
|
|
25
25
|
<svg class="loader" version="1.1" id="L4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
|
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
</div>
|
|
39
39
|
</main>
|
|
40
40
|
<footer>
|
|
41
|
+
<p>
|
|
42
|
+
<a href="./character-test.html">Character test page</a> for complex text: HTML entities, emojis, RTL and LTR, multilingual content.
|
|
43
|
+
</p>
|
|
41
44
|
<div class="content">
|
|
42
45
|
Made with <svg class="heart-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M18 1l-6 4-6-4-6 5v7l12 10 12-10v-7z"/></svg> by Caboodle Tech
|
|
43
46
|
</div>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const loadFoxImage = () => {
|
|
3
2
|
const container = document.getElementById('fox-container');
|
|
4
3
|
if (!container) {
|
|
5
4
|
console.log('DEMO: Could not locate the image container for the fox image.');
|
|
@@ -23,7 +22,7 @@ function loadFoxImage() {
|
|
|
23
22
|
.catch((_) => {
|
|
24
23
|
console.log('DEMO: There was an error trying to load the fox image.');
|
|
25
24
|
});
|
|
26
|
-
}
|
|
25
|
+
};
|
|
27
26
|
|
|
28
27
|
document.addEventListener('DOMContentLoaded', () => {
|
|
29
28
|
console.log('DEMO: Loading a random image of a fox in 3 seconds...');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
const setupChatApp = () => {
|
|
2
2
|
// Make sure the basic elements are present on the page.
|
|
3
3
|
const chatContainer = document.getElementById('chat');
|
|
4
4
|
if (!chatContainer) { return; }
|
|
@@ -28,9 +28,11 @@ function setupChatApp() {
|
|
|
28
28
|
textarea.style.height = `${textarea.scrollHeight}px`;
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
/*
|
|
32
|
+
* Handle websocket messages from the server. NSS demos only use strings so
|
|
33
|
+
* check for that.
|
|
34
|
+
*/
|
|
32
35
|
NSS_WS.registerCallback((msgObj) => {
|
|
33
|
-
// NSS demos only use strings so check for that.
|
|
34
36
|
if (msgObj.type === 'string') {
|
|
35
37
|
// Add the servers response to the chat app.
|
|
36
38
|
const msgDiv = document.createElement('div');
|
|
@@ -43,19 +45,19 @@ function setupChatApp() {
|
|
|
43
45
|
|
|
44
46
|
// When the submit button (send icon) is pressed send a websocket message.
|
|
45
47
|
button.addEventListener('click', () => {
|
|
46
|
-
|
|
48
|
+
/*
|
|
49
|
+
* Send the message. Add the message to the chat app.
|
|
50
|
+
*/
|
|
47
51
|
NSS_WS.send(textarea.value.replace(/\n/g, ' '));
|
|
48
|
-
// Add the message to the chat app.
|
|
49
52
|
const msgDiv = document.createElement('div');
|
|
50
53
|
msgDiv.classList.add('msg');
|
|
51
54
|
msgDiv.classList.add('frontend');
|
|
52
55
|
msgDiv.innerHTML = textarea.value.replace(/\n/g, '<br>');
|
|
53
56
|
msgContainer.appendChild(msgDiv);
|
|
54
|
-
// Reset the chat message box.
|
|
55
57
|
textarea.value = '';
|
|
56
58
|
textarea.style.height = 'initial';
|
|
57
59
|
});
|
|
58
|
-
}
|
|
60
|
+
};
|
|
59
61
|
|
|
60
62
|
// Wait until the page is ready and then setup the demo.
|
|
61
63
|
document.addEventListener('DOMContentLoaded', () => {
|