conextra
Version:
Conextra for Web Development. Helps create a SPWA (Single-page Progressive Web Application).
1,989 lines • 77 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>List of modules</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.markdown-body {
box-sizing: border-box;
min-width: 200px;
max-width: 980px;
margin: 0 auto;
padding: 45px;
}
@media (max-width: 767px) {
.markdown-body {
padding: 15px;
}
}
.markdown-body {
--base-size-4: 0.25rem;
--base-size-8: 0.5rem;
--base-size-16: 1rem;
--base-size-24: 1.5rem;
--base-size-40: 2.5rem;
--base-text-weight-normal: 400;
--base-text-weight-medium: 500;
--base-text-weight-semibold: 600;
--fontStack-monospace: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
--fgColor-accent: Highlight;
}
@media (prefers-color-scheme: dark) {
.markdown-body, [data-theme="dark"] {
/* dark */
color-scheme: dark;
--focus-outlineColor: #1f6feb;
--fgColor-default: #f0f6fc;
--fgColor-muted: #9198a1;
--fgColor-accent: #4493f8;
--fgColor-success: #3fb950;
--fgColor-attention: #d29922;
--fgColor-danger: #f85149;
--fgColor-done: #ab7df8;
--bgColor-default: #0d1117;
--bgColor-muted: #151b23;
--bgColor-neutral-muted: #656c7633;
--bgColor-attention-muted: #bb800926;
--borderColor-default: #3d444d;
--borderColor-muted: #3d444db3;
--borderColor-neutral-muted: #3d444db3;
--borderColor-accent-emphasis: #1f6feb;
--borderColor-success-emphasis: #238636;
--borderColor-attention-emphasis: #9e6a03;
--borderColor-danger-emphasis: #da3633;
--borderColor-done-emphasis: #8957e5;
--color-prettylights-syntax-comment: #9198a1;
--color-prettylights-syntax-constant: #79c0ff;
--color-prettylights-syntax-constant-other-reference-link: #a5d6ff;
--color-prettylights-syntax-entity: #d2a8ff;
--color-prettylights-syntax-storage-modifier-import: #f0f6fc;
--color-prettylights-syntax-entity-tag: #7ee787;
--color-prettylights-syntax-keyword: #ff7b72;
--color-prettylights-syntax-string: #a5d6ff;
--color-prettylights-syntax-variable: #ffa657;
--color-prettylights-syntax-brackethighlighter-unmatched: #f85149;
--color-prettylights-syntax-brackethighlighter-angle: #9198a1;
--color-prettylights-syntax-invalid-illegal-text: #f0f6fc;
--color-prettylights-syntax-invalid-illegal-bg: #8e1519;
--color-prettylights-syntax-carriage-return-text: #f0f6fc;
--color-prettylights-syntax-carriage-return-bg: #b62324;
--color-prettylights-syntax-string-regexp: #7ee787;
--color-prettylights-syntax-markup-list: #f2cc60;
--color-prettylights-syntax-markup-heading: #1f6feb;
--color-prettylights-syntax-markup-italic: #f0f6fc;
--color-prettylights-syntax-markup-bold: #f0f6fc;
--color-prettylights-syntax-markup-deleted-text: #ffdcd7;
--color-prettylights-syntax-markup-deleted-bg: #67060c;
--color-prettylights-syntax-markup-inserted-text: #aff5b4;
--color-prettylights-syntax-markup-inserted-bg: #033a16;
--color-prettylights-syntax-markup-changed-text: #ffdfb6;
--color-prettylights-syntax-markup-changed-bg: #5a1e02;
--color-prettylights-syntax-markup-ignored-text: #f0f6fc;
--color-prettylights-syntax-markup-ignored-bg: #1158c7;
--color-prettylights-syntax-meta-diff-range: #d2a8ff;
--color-prettylights-syntax-sublimelinter-gutter-mark: #3d444d;
}
}
@media (prefers-color-scheme: light) {
.markdown-body, [data-theme="light"] {
/* light */
color-scheme: light;
--focus-outlineColor: #0969da;
--fgColor-default: #1f2328;
--fgColor-muted: #59636e;
--fgColor-accent: #0969da;
--fgColor-success: #1a7f37;
--fgColor-attention: #9a6700;
--fgColor-danger: #d1242f;
--fgColor-done: #8250df;
--bgColor-default: #ffffff;
--bgColor-muted: #f6f8fa;
--bgColor-neutral-muted: #818b981f;
--bgColor-attention-muted: #fff8c5;
--borderColor-default: #d1d9e0;
--borderColor-muted: #d1d9e0b3;
--borderColor-neutral-muted: #d1d9e0b3;
--borderColor-accent-emphasis: #0969da;
--borderColor-success-emphasis: #1a7f37;
--borderColor-attention-emphasis: #9a6700;
--borderColor-danger-emphasis: #cf222e;
--borderColor-done-emphasis: #8250df;
--color-prettylights-syntax-comment: #59636e;
--color-prettylights-syntax-constant: #0550ae;
--color-prettylights-syntax-constant-other-reference-link: #0a3069;
--color-prettylights-syntax-entity: #6639ba;
--color-prettylights-syntax-storage-modifier-import: #1f2328;
--color-prettylights-syntax-entity-tag: #0550ae;
--color-prettylights-syntax-keyword: #cf222e;
--color-prettylights-syntax-string: #0a3069;
--color-prettylights-syntax-variable: #953800;
--color-prettylights-syntax-brackethighlighter-unmatched: #82071e;
--color-prettylights-syntax-brackethighlighter-angle: #59636e;
--color-prettylights-syntax-invalid-illegal-text: #f6f8fa;
--color-prettylights-syntax-invalid-illegal-bg: #82071e;
--color-prettylights-syntax-carriage-return-text: #f6f8fa;
--color-prettylights-syntax-carriage-return-bg: #cf222e;
--color-prettylights-syntax-string-regexp: #116329;
--color-prettylights-syntax-markup-list: #3b2300;
--color-prettylights-syntax-markup-heading: #0550ae;
--color-prettylights-syntax-markup-italic: #1f2328;
--color-prettylights-syntax-markup-bold: #1f2328;
--color-prettylights-syntax-markup-deleted-text: #82071e;
--color-prettylights-syntax-markup-deleted-bg: #ffebe9;
--color-prettylights-syntax-markup-inserted-text: #116329;
--color-prettylights-syntax-markup-inserted-bg: #dafbe1;
--color-prettylights-syntax-markup-changed-text: #953800;
--color-prettylights-syntax-markup-changed-bg: #ffd8b5;
--color-prettylights-syntax-markup-ignored-text: #d1d9e0;
--color-prettylights-syntax-markup-ignored-bg: #0550ae;
--color-prettylights-syntax-meta-diff-range: #8250df;
--color-prettylights-syntax-sublimelinter-gutter-mark: #818b98;
}
}
.markdown-body {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
margin: 0;
color: var(--fgColor-default);
background-color: var(--bgColor-default);
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
font-size: 16px;
line-height: 1.5;
word-wrap: break-word;
}
.markdown-body .octicon {
display: inline-block;
fill: currentColor;
vertical-align: text-bottom;
}
.markdown-body h1:hover .anchor .octicon-link:before,
.markdown-body h2:hover .anchor .octicon-link:before,
.markdown-body h3:hover .anchor .octicon-link:before,
.markdown-body h4:hover .anchor .octicon-link:before,
.markdown-body h5:hover .anchor .octicon-link:before,
.markdown-body h6:hover .anchor .octicon-link:before {
width: 16px;
height: 16px;
content: ' ';
display: inline-block;
background-color: currentColor;
-webkit-mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>");
mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>");
}
.markdown-body details,
.markdown-body figcaption,
.markdown-body figure {
display: block;
}
.markdown-body summary {
display: list-item;
}
.markdown-body [hidden] {
display: none !important;
}
.markdown-body a {
background-color: transparent;
color: var(--fgColor-accent);
text-decoration: none;
}
.markdown-body abbrList of modules {
border-bottom: none;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
.markdown-body b,
.markdown-body strong {
font-weight: var(--base-text-weight-semibold, 600);
}
.markdown-body dfn {
font-style: italic;
}
.markdown-body h1 {
margin: .67em 0;
font-weight: var(--base-text-weight-semibold, 600);
padding-bottom: .3em;
font-size: 2em;
border-bottom: 1px solid var(--borderColor-muted);
}
.markdown-body mark {
background-color: var(--bgColor-attention-muted);
color: var(--fgColor-default);
}
.markdown-body small {
font-size: 90%;
}
.markdown-body sub,
.markdown-body sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
.markdown-body sub {
bottom: -0.25em;
}
.markdown-body sup {
top: -0.5em;
}
.markdown-body img {
border-style: none;
max-width: 100%;
box-sizing: content-box;
}
.markdown-body code,
.markdown-body kbd,
.markdown-body pre,
.markdown-body samp {
font-family: monospace;
font-size: 1em;
}
.markdown-body figure {
margin: 1em var(--base-size-40);
}
.markdown-body hr {
box-sizing: content-box;
overflow: hidden;
background: transparent;
border-bottom: 1px solid var(--borderColor-muted);
height: .25em;
padding: 0;
margin: var(--base-size-24) 0;
background-color: var(--borderColor-default);
border: 0;
}
.markdown-body input {
font: inherit;
margin: 0;
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
.markdown-body [type=button],
.markdown-body [type=reset],
.markdown-body [type=submit] {
-webkit-appearance: button;
appearance: button;
}
.markdown-body [type=checkbox],
.markdown-body [type=radio] {
box-sizing: border-box;
padding: 0;
}
.markdown-body [type=number]::-webkit-inner-spin-button,
.markdown-body [type=number]::-webkit-outer-spin-button {
height: auto;
}
.markdown-body [type=search]::-webkit-search-cancel-button,
.markdown-body [type=search]::-webkit-search-decoration {
-webkit-appearance: none;
appearance: none;
}
.markdown-body ::-webkit-input-placeholder {
color: inherit;
opacity: .54;
}
.markdown-body ::-webkit-file-upload-button {
-webkit-appearance: button;
appearance: button;
font: inherit;
}
.markdown-body a:hover {
text-decoration: underline;
}
.markdown-body ::placeholder {
color: var(--fgColor-muted);
opacity: 1;
}
.markdown-body hr::before {
display: table;
content: "";
}
.markdown-body hr::after {
display: table;
clear: both;
content: "";
}
.markdown-body table {
border-spacing: 0;
border-collapse: collapse;
display: block;
width: max-content;
max-width: 100%;
overflow: auto;
font-variant: tabular-nums;
}
.markdown-body td,
.markdown-body th {
padding: 0;
}
.markdown-body details summary {
cursor: pointer;
}
.markdown-body a:focus,
.markdown-body [role=button]:focus,
.markdown-body input[type=radio]:focus,
.markdown-body input[type=checkbox]:focus {
outline: 2px solid var(--focus-outlineColor);
outline-offset: -2px;
box-shadow: none;
}
.markdown-body a:focus:not(:focus-visible),
.markdown-body [role=button]:focus:not(:focus-visible),
.markdown-body input[type=radio]:focus:not(:focus-visible),
.markdown-body input[type=checkbox]:focus:not(:focus-visible) {
outline: solid 1px transparent;
}
.markdown-body a:focus-visible,
.markdown-body [role=button]:focus-visible,
.markdown-body input[type=radio]:focus-visible,
.markdown-body input[type=checkbox]:focus-visible {
outline: 2px solid var(--focus-outlineColor);
outline-offset: -2px;
box-shadow: none;
}
.markdown-body a:not([class]):focus,
.markdown-body a:not([class]):focus-visible,
.markdown-body input[type=radio]:focus,
.markdown-body input[type=radio]:focus-visible,
.markdown-body input[type=checkbox]:focus,
.markdown-body input[type=checkbox]:focus-visible {
outline-offset: 0;
}
.markdown-body kbd {
display: inline-block;
padding: var(--base-size-4);
font: 11px var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace);
line-height: 10px;
color: var(--fgColor-default);
vertical-align: middle;
background-color: var(--bgColor-muted);
border: solid 1px var(--borderColor-neutral-muted);
border-bottom-color: var(--borderColor-neutral-muted);
border-radius: 6px;
box-shadow: inset 0 -1px 0 var(--borderColor-neutral-muted);
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
margin-top: var(--base-size-24);
margin-bottom: var(--base-size-16);
font-weight: var(--base-text-weight-semibold, 600);
line-height: 1.25;
}
.markdown-body h2 {
font-weight: var(--base-text-weight-semibold, 600);
padding-bottom: .3em;
font-size: 1.5em;
border-bottom: 1px solid var(--borderColor-muted);
}
.markdown-body h3 {
font-weight: var(--base-text-weight-semibold, 600);
font-size: 1.25em;
}
.markdown-body h4 {
font-weight: var(--base-text-weight-semibold, 600);
font-size: 1em;
}
.markdown-body h5 {
font-weight: var(--base-text-weight-semibold, 600);
font-size: .875em;
}
.markdown-body h6 {
font-weight: var(--base-text-weight-semibold, 600);
font-size: .85em;
color: var(--fgColor-muted);
}
.markdown-body p {
margin-top: 0;
margin-bottom: 10px;
}
.markdown-body blockquote {
margin: 0;
padding: 0 1em;
color: var(--fgColor-muted);
border-left: .25em solid var(--borderColor-default);
}
.markdown-body ul,
.markdown-body ol {
margin-top: 0;
margin-bottom: 0;
padding-left: 2em;
}
.markdown-body ol ol,
.markdown-body ul ol {
list-style-type: lower-roman;
}
.markdown-body ul ul ol,
.markdown-body ul ol ol,
.markdown-body ol ul ol,
.markdown-body ol ol ol {
list-style-type: lower-alpha;
}
.markdown-body dd {
margin-left: 0;
}
.markdown-body tt,
.markdown-body code,
.markdown-body samp {
font-family: var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace);
font-size: 12px;
}
.markdown-body pre {
margin-top: 0;
margin-bottom: 0;
font-family: var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace);
font-size: 12px;
word-wrap: normal;
}
.markdown-body .octicon {
display: inline-block;
overflow: visible !important;
vertical-align: text-bottom;
fill: currentColor;
}
.markdown-body input::-webkit-outer-spin-button,
.markdown-body input::-webkit-inner-spin-button {
margin: 0;
appearance: none;
}
.markdown-body .mr-2 {
margin-right: var(--base-size-8, 8px) !important;
}
.markdown-body::before {
display: table;
content: "";
}
.markdown-body::after {
display: table;
clear: both;
content: "";
}
.markdown-body > *:first-child {
margin-top: 0 !important;
}
.markdown-body > *:last-child {
margin-bottom: 0 !important;
}
.markdown-body a:not([href]) {
color: inherit;
text-decoration: none;
}
.markdown-body .absent {
color: var(--fgColor-danger);
}
.markdown-body .anchor {
float: left;
padding-right: var(--base-size-4);
margin-left: -20px;
line-height: 1;
}
.markdown-body .anchor:focus {
outline: none;
}
.markdown-body p,
.markdown-body blockquote,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body table,
.markdown-body pre,
.markdown-body details {
margin-top: 0;
margin-bottom: var(--base-size-16);
}
.markdown-body blockquote > :first-child {
margin-top: 0;
}
.markdown-body blockquote > :last-child {
margin-bottom: 0;
}
.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
color: var(--fgColor-default);
vertical-align: middle;
visibility: hidden;
}
.markdown-body h1:hover .anchor,
.markdown-body h2:hover .anchor,
.markdown-body h3:hover .anchor,
.markdown-body h4:hover .anchor,
.markdown-body h5:hover .anchor,
.markdown-body h6:hover .anchor {
text-decoration: none;
}
.markdown-body h1:hover .anchor .octicon-link,
.markdown-body h2:hover .anchor .octicon-link,
.markdown-body h3:hover .anchor .octicon-link,
.markdown-body h4:hover .anchor .octicon-link,
.markdown-body h5:hover .anchor .octicon-link,
.markdown-body h6:hover .anchor .octicon-link {
visibility: visible;
}
.markdown-body h1 tt,
.markdown-body h1 code,
.markdown-body h2 tt,
.markdown-body h2 code,
.markdown-body h3 tt,
.markdown-body h3 code,
.markdown-body h4 tt,
.markdown-body h4 code,
.markdown-body h5 tt,
.markdown-body h5 code,
.markdown-body h6 tt,
.markdown-body h6 code {
padding: 0 .2em;
font-size: inherit;
}
.markdown-body summary h1,
.markdown-body summary h2,
.markdown-body summary h3,
.markdown-body summary h4,
.markdown-body summary h5,
.markdown-body summary h6 {
display: inline-block;
}
.markdown-body summary h1 .anchor,
.markdown-body summary h2 .anchor,
.markdown-body summary h3 .anchor,
.markdown-body summary h4 .anchor,
.markdown-body summary h5 .anchor,
.markdown-body summary h6 .anchor {
margin-left: -40px;
}
.markdown-body summary h1,
.markdown-body summary h2 {
padding-bottom: 0;
border-bottom: 0;
}
.markdown-body ul.no-list,
.markdown-body ol.no-list {
padding: 0;
list-style-type: none;
}
.markdown-body ol[type="a s"] {
list-style-type: lower-alpha;
}
.markdown-body ol[type="A s"] {
list-style-type: upper-alpha;
}
.markdown-body ol[type="i s"] {
list-style-type: lower-roman;
}
.markdown-body ol[type="I s"] {
list-style-type: upper-roman;
}
.markdown-body ol[type="1"] {
list-style-type: decimal;
}
.markdown-body div > ol:not([type]) {
list-style-type: decimal;
}
.markdown-body ul ul,
.markdown-body ul ol,
.markdown-body ol ol,
.markdown-body ol ul {
margin-top: 0;
margin-bottom: 0;
}
.markdown-body li > p {
margin-top: var(--base-size-16);
}
.markdown-body li + li {
margin-top: .25em;
}
.markdown-body dl {
padding: 0;
}
.markdown-body dl dt {
padding: 0;
margin-top: var(--base-size-16);
font-size: 1em;
font-style: italic;
font-weight: var(--base-text-weight-semibold, 600);
}
.markdown-body dl dd {
padding: 0 var(--base-size-16);
margin-bottom: var(--base-size-16);
}
.markdown-body table th {
font-weight: var(--base-text-weight-semibold, 600);
}
.markdown-body table th,
.markdown-body table td {
padding: 6px 13px;
border: 1px solid var(--borderColor-default);
}
.markdown-body table td > :last-child {
margin-bottom: 0;
}
.markdown-body table tr {
background-color: var(--bgColor-default);
border-top: 1px solid var(--borderColor-muted);
}
.markdown-body table tr:nth-child(2n) {
background-color: var(--bgColor-muted);
}
.markdown-body table img {
background-color: transparent;
}
.markdown-body img[align=right] {
padding-left: 20px;
}
.markdown-body img[align=left] {
padding-right: 20px;
}
.markdown-body .emoji {
max-width: none;
vertical-align: text-top;
background-color: transparent;
}
.markdown-body span.frame {
display: block;
overflow: hidden;
}
.markdown-body span.frame > span {
display: block;
float: left;
width: auto;
padding: 7px;
margin: 13px 0 0;
overflow: hidden;
border: 1px solid var(--borderColor-default);
}
.markdown-body span.frame span img {
display: block;
float: left;
}
.markdown-body span.frame span span {
display: block;
padding: 5px 0 0;
clear: both;
color: var(--fgColor-default);
}
.markdown-body span.align-center {
display: block;
overflow: hidden;
clear: both;
}
.markdown-body span.align-center > span {
display: block;
margin: 13px auto 0;
overflow: hidden;
text-align: center;
}
.markdown-body span.align-center span img {
margin: 0 auto;
text-align: center;
}
.markdown-body span.align-right {
display: block;
overflow: hidden;
clear: both;
}
.markdown-body span.align-right > span {
display: block;
margin: 13px 0 0;
overflow: hidden;
text-align: right;
}
.markdown-body span.align-right span img {
margin: 0;
text-align: right;
}
.markdown-body span.float-left {
display: block;
float: left;
margin-right: 13px;
overflow: hidden;
}
.markdown-body span.float-left span {
margin: 13px 0 0;
}
.markdown-body span.float-right {
display: block;
float: right;
margin-left: 13px;
overflow: hidden;
}
.markdown-body span.float-right > span {
display: block;
margin: 13px auto 0;
overflow: hidden;
text-align: right;
}
.markdown-body code,
.markdown-body tt {
padding: .2em .4em;
margin: 0;
font-size: 85%;
white-space: break-spaces;
background-color: var(--bgColor-neutral-muted);
border-radius: 6px;
}
.markdown-body code br,
.markdown-body tt br {
display: none;
}
.markdown-body del code {
text-decoration: inherit;
}
.markdown-body samp {
font-size: 85%;
}
.markdown-body pre code {
font-size: 100%;
}
.markdown-body pre > code {
padding: 0;
margin: 0;
word-break: normal;
white-space: pre;
background: transparent;
border: 0;
}
.markdown-body .highlight {
margin-bottom: var(--base-size-16);
}
.markdown-body .highlight pre {
margin-bottom: 0;
word-break: normal;
}
.markdown-body .highlight pre,
.markdown-body pre {
padding: var(--base-size-16);
overflow: auto;
font-size: 85%;
line-height: 1.45;
color: var(--fgColor-default);
background-color: var(--bgColor-muted);
border-radius: 6px;
}
.markdown-body pre code,
.markdown-body pre tt {
display: inline;
max-width: auto;
padding: 0;
margin: 0;
overflow: visible;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
}
.markdown-body .csv-data td,
.markdown-body .csv-data th {
padding: 5px;
overflow: hidden;
font-size: 12px;
line-height: 1;
text-align: left;
white-space: nowrap;
}
.markdown-body .csv-data .blob-num {
padding: 10px var(--base-size-8) 9px;
text-align: right;
background: var(--bgColor-default);
border: 0;
}
.markdown-body .csv-data tr {
border-top: 0;
}
.markdown-body .csv-data th {
font-weight: var(--base-text-weight-semibold, 600);
background: var(--bgColor-muted);
border-top: 0;
}
.markdown-body [data-footnote-ref]::before {
content: "[";
}
.markdown-body [data-footnote-ref]::after {
content: "]";
}
.markdown-body .footnotes {
font-size: 12px;
color: var(--fgColor-muted);
border-top: 1px solid var(--borderColor-default);
}
.markdown-body .footnotes ol {
padding-left: var(--base-size-16);
}
.markdown-body .footnotes ol ul {
display: inline-block;
padding-left: var(--base-size-16);
margin-top: var(--base-size-16);
}
.markdown-body .footnotes li {
position: relative;
}
.markdown-body .footnotes li:target::before {
position: absolute;
top: calc(var(--base-size-8)*-1);
right: calc(var(--base-size-8)*-1);
bottom: calc(var(--base-size-8)*-1);
left: calc(var(--base-size-24)*-1);
pointer-events: none;
content: "";
border: 2px solid var(--borderColor-accent-emphasis);
border-radius: 6px;
}
.markdown-body .footnotes li:target {
color: var(--fgColor-default);
}
.markdown-body .footnotes .data-footnote-backref g-emoji {
font-family: monospace;
}
.markdown-body body:has(:modal) {
padding-right: var(--dialog-scrollgutter) !important;
}
.markdown-body .pl-c {
color: var(--color-prettylights-syntax-comment);
}
.markdown-body .pl-c1,
.markdown-body .pl-s .pl-v {
color: var(--color-prettylights-syntax-constant);
}
.markdown-body .pl-e,
.markdown-body .pl-en {
color: var(--color-prettylights-syntax-entity);
}
.markdown-body .pl-smi,
.markdown-body .pl-s .pl-s1 {
color: var(--color-prettylights-syntax-storage-modifier-import);
}
.markdown-body .pl-ent {
color: var(--color-prettylights-syntax-entity-tag);
}
.markdown-body .pl-k {
color: var(--color-prettylights-syntax-keyword);
}
.markdown-body .pl-s,
.markdown-body .pl-pds,
.markdown-body .pl-s .pl-pse .pl-s1,
.markdown-body .pl-sr,
.markdown-body .pl-sr .pl-cce,
.markdown-body .pl-sr .pl-sre,
.markdown-body .pl-sr .pl-sra {
color: var(--color-prettylights-syntax-string);
}
.markdown-body .pl-v,
.markdown-body .pl-smw {
color: var(--color-prettylights-syntax-variable);
}
.markdown-body .pl-bu {
color: var(--color-prettylights-syntax-brackethighlighter-unmatched);
}
.markdown-body .pl-ii {
color: var(--color-prettylights-syntax-invalid-illegal-text);
background-color: var(--color-prettylights-syntax-invalid-illegal-bg);
}
.markdown-body .pl-c2 {
color: var(--color-prettylights-syntax-carriage-return-text);
background-color: var(--color-prettylights-syntax-carriage-return-bg);
}
.markdown-body .pl-sr .pl-cce {
font-weight: bold;
color: var(--color-prettylights-syntax-string-regexp);
}
.markdown-body .pl-ml {
color: var(--color-prettylights-syntax-markup-list);
}
.markdown-body .pl-mh,
.markdown-body .pl-mh .pl-en,
.markdown-body .pl-ms {
font-weight: bold;
color: var(--color-prettylights-syntax-markup-heading);
}
.markdown-body .pl-mi {
font-style: italic;
color: var(--color-prettylights-syntax-markup-italic);
}
.markdown-body .pl-mb {
font-weight: bold;
color: var(--color-prettylights-syntax-markup-bold);
}
.markdown-body .pl-md {
color: var(--color-prettylights-syntax-markup-deleted-text);
background-color: var(--color-prettylights-syntax-markup-deleted-bg);
}
.markdown-body .pl-mi1 {
color: var(--color-prettylights-syntax-markup-inserted-text);
background-color: var(--color-prettylights-syntax-markup-inserted-bg);
}
.markdown-body .pl-mc {
color: var(--color-prettylights-syntax-markup-changed-text);
background-color: var(--color-prettylights-syntax-markup-changed-bg);
}
.markdown-body .pl-mi2 {
color: var(--color-prettylights-syntax-markup-ignored-text);
background-color: var(--color-prettylights-syntax-markup-ignored-bg);
}
.markdown-body .pl-mdr {
font-weight: bold;
color: var(--color-prettylights-syntax-meta-diff-range);
}
.markdown-body .pl-ba {
color: var(--color-prettylights-syntax-brackethighlighter-angle);
}
.markdown-body .pl-sg {
color: var(--color-prettylights-syntax-sublimelinter-gutter-mark);
}
.markdown-body .pl-corl {
text-decoration: underline;
color: var(--color-prettylights-syntax-constant-other-reference-link);
}
.markdown-body [role=button]:focus:not(:focus-visible),
.markdown-body [role=tabpanel][tabindex="0"]:focus:not(:focus-visible),
.markdown-body button:focus:not(:focus-visible),
.markdown-body summary:focus:not(:focus-visible),
.markdown-body a:focus:not(:focus-visible) {
outline: none;
box-shadow: none;
}
.markdown-body [tabindex="0"]:focus:not(:focus-visible),
.markdown-body details-dialog:focus:not(:focus-visible) {
outline: none;
}
.markdown-body g-emoji {
display: inline-block;
min-width: 1ch;
font-family: "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
font-size: 1em;
font-style: normal !important;
font-weight: var(--base-text-weight-normal, 400);
line-height: 1;
vertical-align: -0.075em;
}
.markdown-body g-emoji img {
width: 1em;
height: 1em;
}
.markdown-body .task-list-item {
list-style-type: none;
}
.markdown-body .task-list-item label {
font-weight: var(--base-text-weight-normal, 400);
}
.markdown-body .task-list-item.enabled label {
cursor: pointer;
}
.markdown-body .task-list-item + .task-list-item {
margin-top: var(--base-size-4);
}
.markdown-body .task-list-item .handle {
display: none;
}
.markdown-body .task-list-item-checkbox {
margin: 0 .2em .25em -1.4em;
vertical-align: middle;
}
.markdown-body ul:dir(rtl) .task-list-item-checkbox {
margin: 0 -1.6em .25em .2em;
}
.markdown-body ol:dir(rtl) .task-list-item-checkbox {
margin: 0 -1.6em .25em .2em;
}
.markdown-body .contains-task-list:hover .task-list-item-convert-container,
.markdown-body .contains-task-list:focus-within .task-list-item-convert-container {
display: block;
width: auto;
height: 24px;
overflow: visible;
clip: auto;
}
.markdown-body ::-webkit-calendar-picker-indicator {
filter: invert(50%);
}
.markdown-body .markdown-alert {
padding: var(--base-size-8) var(--base-size-16);
margin-bottom: var(--base-size-16);
color: inherit;
border-left: .25em solid var(--borderColor-default);
}
.markdown-body .markdown-alert > :first-child {
margin-top: 0;
}
.markdown-body .markdown-alert > :last-child {
margin-bottom: 0;
}
.markdown-body .markdown-alert .markdown-alert-title {
display: flex;
font-weight: var(--base-text-weight-medium, 500);
align-items: center;
line-height: 1;
}
.markdown-body .markdown-alert.markdown-alert-note {
border-left-color: var(--borderColor-accent-emphasis);
}
.markdown-body .markdown-alert.markdown-alert-note .markdown-alert-title {
color: var(--fgColor-accent);
}
.markdown-body .markdown-alert.markdown-alert-important {
border-left-color: var(--borderColor-done-emphasis);
}
.markdown-body .markdown-alert.markdown-alert-important .markdown-alert-title {
color: var(--fgColor-done);
}
.markdown-body .markdown-alert.markdown-alert-warning {
border-left-color: var(--borderColor-attention-emphasis);
}
.markdown-body .markdown-alert.markdown-alert-warning .markdown-alert-title {
color: var(--fgColor-attention);
}
.markdown-body .markdown-alert.markdown-alert-tip {
border-left-color: var(--borderColor-success-emphasis);
}
.markdown-body .markdown-alert.markdown-alert-tip .markdown-alert-title {
color: var(--fgColor-success);
}
.markdown-body .markdown-alert.markdown-alert-caution {
border-left-color: var(--borderColor-danger-emphasis);
}
.markdown-body .markdown-alert.markdown-alert-caution .markdown-alert-title {
color: var(--fgColor-danger);
}
.markdown-body > *:first-child > .heading-element:first-child {
margin-top: 0 !important;
}
.markdown-body .highlight pre:has(+.zeroclipboard-container) {
min-height: 52px;
}
</style>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-12">
<h1 class="text-center">Conextra Framework</h1>
<p class="text-center">Documentation for Conextra framework modules</p>
</div>
</div>
<div class="row w-100">
<div class="col-3 d-none d-lg-inline">
<div class="sticky-top overflow-auto vh-100">
<div id="list-headers" class="list-group mt-5">
<p>
<a href="#config-sets-module">'<strong>config-sets</strong>' module</a>
<a href="#data-context-module">'<strong>data-context</strong>' module</a>
<a href="#data-context-binding-module">'<strong>data-context-binding</strong>' module</a>
<a href="#tiny-https-server-module">'<strong>tiny-https-server</strong>' module</a>
<a href="#url-fragment-extender-module">'<strong>url-fragment-extender</strong>' module</a>
<a href="#ws13-module">'<strong>ws13</strong>' module</a>
<a href="#ws-user-module">'<strong>ws-user</strong>' module</a>
</p>
</div>
</div>
</div>
<div class="col col-lg-9">
<div class="p-2 markdown-body" data-bs-spy="scroll" data-bs-target="#list-headers" data-bs-offset="0" tabindex="0">
<h1 id="list-of-modules">List of modules</h1>
<p>
This is a list of modules that are part of the Conextra framework.<br>
Conextra is a framework for building web applications using Node.js and WebSocket.<br>
</p>
<pre><code>Conextra Power for web development:
- module 'config-sets' configure and change app settings in real-time
- module 'data-context' monitoring data changes
- module 'data-context-binding' bind data to DOM elements
- module 'tiny-https-server' SPA and PWA services
- module 'url-fragment-extender' manage URL fragments
- module 'ws13' create WebSocket connection
- module 'ws-user' manage users over WebSocket
</code></pre>
<p>
It helps you create SPWA (Single-page Progressive Web Application) and efficiently perform real-time updates over WebSocket.<br>
The modules are designed to work together to provide a complete solution for building SPAs and PWAs.<br>
</p>
<h2 id="config-sets-module">'config-sets' module</h2>
<p>
<img src="https://img.shields.io/npm/l/config-sets" alt="NPM License" />
<img src="https://img.shields.io/npm/v/config-sets" alt="NPM Version" />
<img src="https://img.shields.io/npm/last-update/config-sets" alt="NPM Last Update" />
<img src="https://img.shields.io/npm/dt/config-sets" alt="NPM Total Downloads" />
</p>
<p>
This manual is also available in <a href="https://manuel-lohmus.github.io/config-sets/README.html">HTML5</a>.<br><br>
This Node.js module manages configuration settings by reading from and writing to a config-sets.json file.<br>
It handles command-line arguments and watches for changes to the configuration file.<br>
It allows you to create applications that can be configured in real time.<br>
</p>
<h3 id="install-of-config-sets-module">Install of 'config-sets' module</h3>
<p><code>npm install config-sets</code></p>
<h3 id="basic-usage-of-config-sets-module">Basic Usage of 'config-sets' module</h3>
<p>
Application settings are stored in a JSON file named config-sets.json.<br>
The file is located in the same directory as the application.<br>
The JSON file contains the following properties:<br>
</p>
<ul>
<li>isProduction: true/false</li>
<li>production: </li>
<li>development: </li>
</ul>
<pre><code class="language-javascript">'use strict';
//Import the required modules.
const configSets = require('config-sets');
// Setup the configuration.
//Automatically read the config-sets.json file.
//Metadata is optional. If you would like to add a comment to the key, use the '-metadata-key' format.
const config = configSets({
'-metadata-key1': ' key1 comment ',
key1: 'value1',
'-metadata-key2': ' key2 comment ',
key2: 'value2'
});
//Example of using in code.
if (config.key1 === 'value1') { ... }
//Example of using the module configuration.
//This allows you to get the module settings from the config-sets.json file.
const moduleConfig = configSets('moduleName', { key1: 'value1', key2: 'value2' });
console.log(moduleConfig);
//Watch 'key1' property for changes.
//Return true to continue watching, false to stop watching.
config.on('key1', function (ev) { console.log(ev); return true; });
</code></pre>
<p>file: <code>config-sets.json</code></p>
<pre><code class="language-json">{
"isProduction": true,
"production": {
/* key1 comment */
"key1": "value1",
/* key2 comment */
"key2": "value2",
"moduleName": {
"key1": "value1",
"key2": "value2"
}
},
"development": {}
}
</code></pre>
<h2 id="data-context-module">'data-context' module</h2>
<p>
<img src="https://img.shields.io/npm/l/data-context" alt="NPM License" />
<img src="https://img.shields.io/npm/v/data-context" alt="NPM Version" />
<img src="https://img.shields.io/npm/last-update/data-context" alt="NPM Last Update" />
<img src="https://img.shields.io/npm/dt/data-context" alt="NPM Total Downloads" />
</p>
<p>
This manual is also available in <a href="https://manuel-lohmus.github.io/data-context/README.html">HTML5</a>.<br><br>
This Node.js module monitors data changes in a data context and notifies listeners when changes occur.<br>
</p>
<h3 id="install-of-data-context-module">Install of 'data-context' module</h3>
<p><code>npm install config-sets</code></p>
<h3 id="basic-usage-of-data-context-module">Basic Usage of 'data-context' module</h3>
<p>node.js example:</p>
<pre><code class="language-javascript">'use strict';
//Import the required modules.
const { createDataContext, parse } = require('data-context');
//import { createDataContext, parse } from "data-context";
//Create a JSON string.
var strJSON = `{
"count": 0
}`;
//Interval id.
var intervalId = null;
//Create data context.
const context = parse(
//Parse the JSON string.
strJSON,
//Reviver function. Create data context.
createDataContext
);
//Listen to the count property.
context.on('count', (event) => {
console.log('event:', event);
if (event.newValue > 10) {
console.log('I am dead.');
clearInterval(intervalId);
//I am dead. Remove listener.
return false;
}
//I am live. Continue listening.
return true;
});
context.on('-change', (event) => {
//Stringify the changes.
var str = context.stringifyChanges(
//Reviver function. Default is null.
null,
//Indentation. Default is 0.
4,
//Include only modified data. Default is true.
true,
//Set data to unmodified after stringification. Default is true.
true
);
console.log('changes:', str);
//I am live. Continue listening.
return true;
});
//Start the interval.
intervalId = setInterval(() => {
//Increment the count property.
context.count++;
}, 1000);
</code></pre>
<p>browser example:</p>
<pre><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>data-context</title>
<!-- STEP 1. Import the module. Import for an HTML page hosted on the server. -->
<script type="text/javascript" src="./index.js"></script>
<!-- STEP 1. Import the module. Import for a standalone HTML page. -->
<!--<script src="https://cdn.jsdelivr.net/npm/data-context"></script>-->
<script>
'use strict';
// STEP 3. Import the module.
importModules(['data-context'], function (DC) {
var { createDataContext, parse } = DC;
//Create a JSON string.
var strJSON = `{
"count": 0
}`;
//Interval id.
var intervalId = null;
//Create data context.
const context = parse(
//Parse the JSON string.
strJSON,
//Reviver function. Create data context.
createDataContext
);
//Listen to the count property.
context.on('count', (event) => {
console.log('event:', event);
if (event.newValue > 10) {
console.log('I am dead.');
clearInterval(intervalId);
//I am dead. Remove listener.
return false;
}
//I am live. Continue listening.
return true;
});
context.on('-change', (event) => {
//Stringify the changes.
var str = context.stringifyChanges(
//Reviver function. Default is null.
null,
//Indentation. Default is 0.
4,
//Include only modified data. Default is true.
true,
//Set data to unmodified after stringification. Default is true.
true
);
console.log('changes:', str);
//I am live. Continue listening.
return true;
});
//Start the interval.
intervalId = setInterval(() => {
//Increment the count property.
context.count++;
}, 1000);
});
// STEP 2. Add module import function.
/**
* Module import function.
* @param {string[]} importIdentifierArray Modules to import.
* @param {(...importModules:any[]) => void} callback Callback function.
*/
function importModules(importIdentifierArray, callback) {
var thisScope = "undefined" != typeof globalThis
? globalThis
: "undefined" != typeof window
? window
: "undefined" != typeof global
? global : "undefined" != typeof self
? self
: {};
if (!thisScope.modules) { thisScope.modules = {}; }
waitModules();
function waitModules() {
if (importIdentifierArray.length) {
for (let i = 0; i < importIdentifierArray.length; i++) {
if (!thisScope.modules[importIdentifierArray[i]]) { return setTimeout(waitModules, 10); }
}
}
callback.call(thisScope, ...importIdentifierArray.map(function (id) { return thisScope.modules[id]; }));
}
}
</script>
</head>
<body>
<h3>Example 'data-context'</h3>
<p>Press F12. Console results.</p>
</body>
</html>
</code></pre>
<h2 id="data-context-binding-module">'data-context-binding' module</h2>
<p>
<img src="https://img.shields.io/npm/l/data-context-binding" alt="NPM License" />
<img src="https://img.shields.io/npm/v/data-context-binding" alt="NPM Version" />
<img src="https://img.shields.io/npm/last-update/data-context-binding" alt="NPM Last Update" />
<img src="https://img.shields.io/npm/dt/data-context-binding" alt="NPM Total Downloads" />
</p>
<p>
This manual is also available in <a href="https://manuel-lohmus.github.io/data-context-binding/README.html">HTML5</a>.<br><br>
Data context binding library for browser.<br>
This library is used to bind data to DOM elements and update the DOM when the data changes.<br>
</p>
<h3 id="basic-usage-of-data-context-binding-module">Basic Usage of 'data-context-binding' module</h3>
<p><a href="https://manuel-lohmus.github.io/data-context-binding/examples/hello-world.html">hello-world.html</a>:</p>
<pre><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>data-context-binding</title>
<!-- STEP 1. Import the modules 'data-context' and 'data-context-binding'.
Import for an HTML page hosted on the server. -->
<!--<script src="./datacontext.js"></script>-->
<!--<script src="./browser.js"></script>-->
<!-- STEP 1. Import the modules 'data-context' and 'data-context-binding'.
Import for a standalone HTML page. -->
<script async src="https://cdn.jsdelivr.net/npm/data-context"></script>
<script async src="https://cdn.jsdelivr.net/npm/data-context-binding"></script>
<!-- STEP 2. Add the data to a container with the ID 'data'. Its contents will be read automatically. -->
<script id="data" type="application/json">
{
"doc": {
/* 1: The metadata-title context object */
/* 2: The metadata-title context object */
"title": "Hello World", // The title comment
/* The metadata-description context object */
"description": "This is a simple example of data context binding.", // The description comment
/* { "hidden": "This is a must be hidden value." } */
"debug": false
}
}
</script>
</head>
<body>
<!-- STEP 3. Bind data to the DOM elements.
In this container we use the 'doc' object.
The 'path' attribute is part of property path. -->
<div path="doc">
<div>
<!-- STEP 3. Bind data to the DOM elements.
The `path` attribute is property path in the data object.
The `bind` attribute is performed data binding. -->
<h1 path="title" bind>Title</h1>
<!-- STEP 3. Bind data to the DOM elements.
The `path` attribute is property path in the data object.
The `bind` attribute is performed data binding. -->
<p path="description" bind>Description</p>
</div>
</div>
<hr />
<h3>Edit the values:</h3>
<label for="title">Title:</label>
<br />
<!-- STEP 3. Bind data to the DOM elements.
The `path` attribute is property path in the data object.
The `bind` attribute is performed data binding. -->
<input type="text" path="doc.title" bind style="width:380px" />
<br />
<br />
<label>Description:</label>
<br />
<!-- STEP 3. Bind data to the DOM elements.
The `path` attribute is property path in the data object.
The `bind` attribute is performed data binding. -->
<input type="text" path="doc.description" bind style="width:380px" />
<hr />
<label>Live changes:</label>
<br />
<!-- STEP 3. Bind data to the DOM elements.
The `bind` attribute is performed data binding.
Listens for data context changes -->
<textarea cols="50" rows="10" bind="change"></textarea>
</body>
</html>
</code></pre>
<h2 id="tiny-https-server-module">'tiny-https-server' module</h2>
<p>
<img src="https://img.shields.io/npm/l/tiny-https-server" alt="NPM License" />
<img src="https://img.shields.io/npm/v/tiny-https-server" alt="NPM Version" />
<img src="https://img.shields.io/npm/last-update/tiny-https-server" alt="NPM Last Update" />
<img src="https://img.shields.io/npm/dt/tiny-https-server" alt="NPM Total Downloads" />
</p>
<p>
This manual is also available in <a href="https://manuel-lohmus.github.io/tiny-https-server/README.html">HTML5</a>.<br><br>
Tiny web server is disain for SPA (Single Page Application).<br>
A tiny web server serves static files, supports HTTPS, subdomains, middleware, and service workers.<br>
</p>
<h3 id="install-of-tiny-https-server-module">Install of 'tiny-https-server' module</h3>
<p><code>npm install tiny-https-server</code></p>
<h3 id="basic-usage-of-tiny-https-server-module">Basic Usage of 'tiny-https-server' module</h3>
<p>You can use tiny-https-server in your project like this:</p>
<pre><code class="language-javascript">const WebCluster = require('tiny-https-server');
consr cluster = WebCluster({
isDebug: true, // Enable debug mode to see logs in the console
parallelism: 'auto 2' // Start 2 workers and scale up and down automatically
}, function _initServer(server) {
// Add a request handler for the /hello path
server.on('request', (req, res, next) => {
if (req.url === '/hello') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World');
return;
}
next();
});
});
</code></pre>
<h2 id="url-fragment-extender-module">'url-fragment-extender' module</h2>
<p>
<img src="https://img.shields.io/npm/l/url-fragment-extender" alt="NPM License" />
<img src="https://img.shields.io/npm/v/url-fragment-extender" alt="NPM Version" />
<img src="https://img.shields.io/npm/last-update/url-fragment-extender" alt="NPM Last Update" />
<img src="https://img.shields.io/npm/dt/url-fragment-extender" alt="NPM Total Downloads" />
</p>
<p>
This manual is also available in <a href="https://manuel-lohmus.github.io/url-fragment-extender/README.html">HTML5</a>.<br><br>
This allows for easy manipulation and extension of URL fragments, as well as handling custom events based on the URL hash.
</p>
<h3 id="install-of-url-fragment-extender-module">Install of 'url-fragment-extender' module</h3>
<p>You can install 'url-fragment-extender' using this command:</p>
<p><code>npm install url-fragment-extender</code></p>
<p>and use in browser 'tiny-https-server' router:</p>
<p><code><script async src="node_modules/url-fragment-extender@2"></script></code></p>
<p>or:</p>
<p><code><script src="https://cdn.jsdelivr.net/npm/url-fragment-extender" ></script></code></p>
<h3 id="basic-usage-of-tiny-https-server-module-1">Basic Usage of 'tiny-https-server' module</h3>
<pre><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>url-fragment-extender</title>
<!-- STEP 1. Import the modules 'url-fragment-extender'.
Import for an HTML page hosted on the server. -->
<script async type="text/javascript" src="./browser.js"></script>
<!-- STEP 1. Import the modules 'url-fragment-extender'.
Import for a standalone HTML page. -->
<!--<script async src="https://cdn.jsdelivr.net/npm/url-fragment-extender"></script>-->
<script>
// STEP 3. Import the module.
importModules(['url-fragment-extender'], function (UFE) {
UFE.on('', function (event) {
$('#content').innerHTML = '';
//I am live. Continue listening.
return true;
});
UFE.on('temp_1', function (event) {
$('#content').innerHTML = $('#temp_1').innerHTML;
//I am live. Continue listening.
return true;
});
UFE.on('temp_2', function (event) {
$('#content').innerHTML = $('#temp_2').innerHTML;
//I am live. Continue listening.
return true;
});
UFE.on('temp_3', function (event) {
$('#content').innerHTML = $('#temp_3').innerHTML;
//I am live. Continue listening.
return true;
});
});
// STEP 2. Add module import function.
/**
* Module import function - step 2.
* @param {string[]} importIdentifierArray Modules to import.
* @param {(...importModules:any[]) => void} callback Callback function.
*/
function importModules(importIdentifierArray, cb) {
var thisScope = "undefined" != typeof globalThis
? globalThis
: "undefined" != typeof window
? window
: "undefined" != typeof global
? global : "undefined" != typeof self
? self
: {};
if (!thisScope.modules) { thisScope.modules = {}; }
waitModules();
function waitModules() {
if (importIdentifierArray.length) {
for (let i = 0; i < importIdentifierArray.length; i++) {
if (!thisScope.modules[importIdentifierArray[i]]) { return setTimeout(waitModules, 10); }
}
}
cb.call(thisScope, ...importIdentifierArray.map(function (id) { return thisScope.modules[id]; }));
}
}
function $(selector, element) { return (element || document).querySelector(selector); }
</script>
<style>
.button {
display: inline-block;
padding: 10px 20px;
font-size: 16px;
color: #fff;
background-color: #007bff;
text-align: center;
text-decoration: none;
border-radius: 5px;
transition: background-color 0.3s ease;
margin: 5px;
}
.button:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<div>
<a class="button" href="#temp_1">template 1</a>
<a class="button" href="#temp_2">template 2</a>
<a class="button" href="#temp_3">template 3</a>
</div>
<br />
<div id="content"></div>
<template id="temp_1">
<div style="background-color:darkgreen;color:whitesmoke"><h1>template 1</h1></div>
</template>
<template id="temp_2">
<div style="background-color:burlywood;color:darkslateblue"><h2>template 2</h2></div>
</template>
<template id="temp_3">
<div><h3>template 3</h3></div>
</template>
</body>
</html>
</code></pre>
<h2 id="ws13-module">'ws13' module</h2>
<p>
<img src="https://img.shields.io/npm/l/ws13" alt="NPM License" />
<img src="https://img.shields.io/npm/v/ws13" alt="NPM Version" />
<img src="https://img.shields.io/npm/last-update/ws13" alt="NPM Last Update" />
<img src="https://img.shields.io/npm/dt/ws13" alt="NPM Total Downloads" />
</p>
<p>
This manual is also available in <a href="https://manuel-lohmus.github.io/ws13/README.html">HTML5</a>.<br><br>
The WebSocket API is an advanced technology that makes it possible to open a two-way interactive communication session between the user's browser and a server.
With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply.
</p>
<h3 id="install-of-ws13-module">Install of 'ws13' module</h3>
<p><code>npm install ws13</code></p>
<h3 id="basic-usage-of-ws13-module">Basic Usage of 'ws13' module</h3>
<p>Example of use on a server:</p>
<pre><code class="language-javascript">const { createServer } = require('node:http');
const createWebSocket = require('ws13');
const server = createServer();
let wsList = [];
server.on('upgrade', function (request) {
// upgrade WebSocket
const websocket = createWebSocket({ request });
// has WebSocket, the handshake is done
if (websocket) {
// inserts a WebSocket from the list
wsList.push(websocket);
// add listeners
websocket
.on('error', console.error)
.on('open', function () {
/* now you can send and receive messages */
})
.on('message', function (event) {
// send to everyone
wsList.forEach((ws) => { ws.send(event.data); });
})
.on('close', function () {
// removing a WebSocket from the list
wsList = wsList.filter(ws => ws !== websocket);
});
} else {
// handshake not accepted
request.destroy();
}
});
</code></pre>
<h2 id="ws-user-module">'ws-user' module</h2>
<p>
<img src="https://img.shields.io/npm/l/ws-user" alt="NPM License" />
<img src="https://img.shields.io/npm/v/ws-user" alt="NPM Version" />
<img src="https://img.shields.io/npm/last-update/ws-user" alt="NPM Last Update" />
<img src="https://img.shields.io/npm/dt/ws-user" alt="NPM Total Downloads" />
</p>
<p>
This manual is also available in <a href="https://manuel-lohmus.github.io/ws-user/README.html">HTML5</a>.<br><br>
This module is used to manage users over WebSocket.<br>
It allows you to create a user manager that can handle user authentication and authorization.<br>
</p>
<h3 id="install-of-ws-user-module">Install of 'ws-user' module</h3>
<p><code>npm install ws-user</code></p>
<h3 id="basic-usage-of-ws-user-module">Basic Usage of 'ws-user' module</h3>
<p>
Use the 'ws-user' module analogous to the 'ws13' module.<br>
Example of use on a server:
</p>
<pre><code class="language-javascript">const { createServer } = require('node:http');
const { createUserManager } = require('ws-user');
const server = createServer();
server.on('upgrade', function (request) {
const wsUser = CreateWsUser(request);
if (wsUser) {
wsUser.onerror = (error) => {
console.error(error);
};
wsUser.onopen = () => {
console.log('Server started');
};
wsUser.onclose = () => {
console.log('Server closed');
};
wsUser.onmessage = (event) => {
// Received message from client and websocket is paused, disable to receive messages
console.log(event.data);
wsUser.messageHandled(); // continue, websocket is open, enable to receive messages
};
wsUser.extensionCommands = {
'myCommand': (event) => {
console.log(event);
const myData = event.message; // Received `myData` from client
// Do something
// Send response to client
wsUser.send(`$myCommand:${myData}`);
event.done(); // or wsUser.messageHandled(); `myCommand` is handled > continue, websocket is open
}
};
}
});
</code></pre>
<br>
<br>
<br>
</div>
</div>
</div>
</div>
<script>
(function () {
'use strict';
var isIE = !!document.documentMode; // Detect IE
if (!isIE) {
var link, script;
// bootstrap for styling (https://getbootstrap.com/)
link = document.createElement('link');
link.href = 'https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.min.css';
link.rel = 'stylesheet';
link.crossOrigin = 'anonymous';
document.head.appendChild(link);
script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/bootstrap@5/dist/js/bootstrap.bundle.min.js';
script.crossOrigin = 'anonymous';
document.head.appendChild(script);
// prism syntax highlighter for code blocks (https://prismjs.com/)
link = document.createElement('link');
link.href = 'https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css';
link.rel = 'stylesheet';
link.crossOrigin = 'anonymous';
document.head.appendChild(link);
script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js';
script.crossOrigin = 'anonymous';
document.head.appendChild(script);
// list-group style for headers
document.querySelectorAll('#list-headers a')
.forEach(function (a) { a.classList.add('list-group-item', 'list-group-item-action') });
}
})();
</script>
</body>
</html>