├── .idea
├── .name
├── vcs.xml
└── misc.xml
├── gradle.properties
├── site
├── .gitignore
├── .kobweb
│ ├── site
│ │ ├── favicon.ico
│ │ ├── gtag.js
│ │ ├── vs.css
│ │ ├── lightfair.css
│ │ ├── intellij-light.css
│ │ ├── cupertino.css
│ │ ├── google-light.css
│ │ ├── FileSaver.js
│ │ ├── logo.svg
│ │ ├── index.html
│ │ ├── highlight.min.js
│ │ └── dom-to-image.js
│ └── conf.yaml
├── src
│ ├── jsMain
│ │ ├── resources
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── gtag.js
│ │ │ │ ├── vs.css
│ │ │ │ ├── lightfair.css
│ │ │ │ ├── intellij-light.css
│ │ │ │ ├── cupertino.css
│ │ │ │ ├── google-light.css
│ │ │ │ ├── FileSaver.js
│ │ │ │ ├── logo.svg
│ │ │ │ ├── highlight.min.js
│ │ │ │ └── dom-to-image.js
│ │ │ └── README.md
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── stevdza
│ │ │ └── san
│ │ │ ├── util
│ │ │ └── Res.kt
│ │ │ ├── model
│ │ │ └── EditorTheme.kt
│ │ │ ├── MyApp.kt
│ │ │ ├── pages
│ │ │ └── Index.kt
│ │ │ └── components
│ │ │ ├── Footer.kt
│ │ │ ├── Editor.kt
│ │ │ └── ControlsView.kt
│ └── jvmMain
│ │ └── kotlin
│ │ └── com
│ │ └── stevdza
│ │ └── san
│ │ └── api
│ │ └── README.md
└── build.gradle.kts
├── gradle
├── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
└── libs.versions.toml
├── README.md
├── settings.gradle.kts
├── .gitignore
├── gradlew.bat
└── gradlew
/.idea/.name:
--------------------------------------------------------------------------------
1 | san
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 |
--------------------------------------------------------------------------------
/site/.gitignore:
--------------------------------------------------------------------------------
1 | # Kobweb ignores
2 | .kobweb/*
3 | !.kobweb/conf.yaml
4 | !.kobweb/site
5 |
--------------------------------------------------------------------------------
/site/.kobweb/site/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevdza-san/EditorApp/HEAD/site/.kobweb/site/favicon.ico
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevdza-san/EditorApp/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevdza-san/EditorApp/HEAD/site/src/jsMain/resources/public/favicon.ico
--------------------------------------------------------------------------------
/site/src/jvmMain/kotlin/com/stevdza/san/api/README.md:
--------------------------------------------------------------------------------
1 | Define API routes in here.
2 |
3 | See also: https://github.com/varabyte/kobweb#define-api-routes
4 |
--------------------------------------------------------------------------------
/site/.kobweb/site/gtag.js:
--------------------------------------------------------------------------------
1 | window.dataLayer = window.dataLayer || [];
2 | function gtag(){dataLayer.push(arguments);}
3 | gtag('js', new Date());
4 | gtag('config', 'G-M6NQ3C6B4S');
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/gtag.js:
--------------------------------------------------------------------------------
1 | window.dataLayer = window.dataLayer || [];
2 | function gtag(){dataLayer.push(arguments);}
3 | gtag('js', new Date());
4 | gtag('config', 'G-M6NQ3C6B4S');
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/site/src/jsMain/resources/README.md:
--------------------------------------------------------------------------------
1 | Define markdown pages under a markdown/ folder, and
2 | they will get picked up and converted to html.
3 |
4 | You must have enabled markdown on this project for this
5 | feature to work.
6 |
7 | See also: https://github.com/varabyte/kobweb#markdown
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pretty-KO - Web App built with Kotlin and Jetpack Compose (Kobweb framework)
2 |
3 | YouTube Video Tutorial
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
5 | maven("https://us-central1-maven.pkg.dev/varabyte-repos/public")
6 | }
7 | }
8 |
9 | rootProject.name = "san"
10 |
11 | include(":site")
12 |
--------------------------------------------------------------------------------
/site/.kobweb/conf.yaml:
--------------------------------------------------------------------------------
1 | site:
2 | title: "Pretty-KO"
3 |
4 | server:
5 | files:
6 | dev:
7 | contentRoot: "build/processedResources/js/main/public"
8 | script: "build/developmentExecutable/san.js"
9 | api: "build/libs/san.jar"
10 | prod:
11 | script: "build/distributions/san.js"
12 | siteRoot: ".kobweb/site"
13 |
14 | port: 8080
--------------------------------------------------------------------------------
/site/src/jsMain/kotlin/com/stevdza/san/util/Res.kt:
--------------------------------------------------------------------------------
1 | package com.stevdza.san.util
2 |
3 | object Res {
4 | object Image {
5 | const val logo = "logo.svg"
6 | }
7 | object Id {
8 | const val editor = "editor"
9 | const val fontSize = "font-size"
10 | const val lineHeight = "line-height"
11 | const val padding = "padding"
12 | }
13 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # General ignores
2 | .DS_Store
3 | build
4 | out
5 | kotlin-js-store
6 |
7 | # IntelliJ ignores
8 | *.iml
9 | /*.ipr
10 |
11 | /.idea/caches
12 | /.idea/libraries
13 | /.idea/modules.xml
14 | /.idea/workspace.xml
15 | /.idea/gradle.xml
16 | /.idea/navEditor.xml
17 | /.idea/assetWizardSettings.xml
18 | /.idea/artifacts
19 | /.idea/compiler.xml
20 | /.idea/jarRepositories.xml
21 | /.idea/*.iml
22 | /.idea/modules
23 | /.idea/libraries-with-intellij-classes.xml
24 |
25 | # Gradle ignores
26 | .gradle
27 |
28 |
--------------------------------------------------------------------------------
/site/src/jsMain/kotlin/com/stevdza/san/model/EditorTheme.kt:
--------------------------------------------------------------------------------
1 | package com.stevdza.san.model
2 |
3 | import org.jetbrains.compose.web.css.CSSColorValue
4 | import org.jetbrains.compose.web.css.rgb
5 |
6 | enum class EditorTheme(val color: CSSColorValue) {
7 | RoyalBlue(color = rgb(r = 28, g = 181, b = 224)),
8 | SeaGreen(color = rgb(r = 28, g = 224, b = 153)),
9 | WickedRed(color = rgb(r = 224, g = 28, b = 28)),
10 | ModernPurple(color = rgb(r = 138, g = 28, b = 224))
11 | }
12 |
13 | enum class Theme(val color: CSSColorValue) {
14 | Red(color = rgb(r = 255, g = 95, b = 86)),
15 | Yellow(color = rgb(r = 255, g = 189, b = 46)),
16 | Green(color = rgb(r = 39, g = 201, b = 63))
17 | }
--------------------------------------------------------------------------------
/site/src/jsMain/kotlin/com/stevdza/san/MyApp.kt:
--------------------------------------------------------------------------------
1 | package com.stevdza.san
2 |
3 | import androidx.compose.runtime.*
4 | import com.varabyte.kobweb.compose.ui.modifiers.*
5 | import com.varabyte.kobweb.core.App
6 | import com.varabyte.kobweb.silk.init.InitSilk
7 | import com.varabyte.kobweb.silk.init.InitSilkContext
8 | import com.varabyte.kobweb.silk.SilkApp
9 | import com.varabyte.kobweb.silk.components.layout.Surface
10 | import com.varabyte.kobweb.silk.components.style.common.SmoothColorStyle
11 | import com.varabyte.kobweb.silk.components.style.toModifier
12 | import org.jetbrains.compose.web.css.*
13 |
14 | @InitSilk
15 | fun updateTheme(ctx: InitSilkContext) {
16 | // Configure silk here
17 | }
18 |
19 | @App
20 | @Composable
21 | fun MyApp(content: @Composable () -> Unit) {
22 | SilkApp {
23 | Surface(SmoothColorStyle.toModifier().minWidth(100.vw).minHeight(100.vh)) {
24 | content()
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | jetbrains-compose = "1.4.0"
3 | kobweb = "0.13.0"
4 | kotlin = "1.8.20"
5 |
6 | [libraries]
7 | kobweb-api = { module = "com.varabyte.kobweb:kobweb-api", version.ref = "kobweb" }
8 | kobweb-core = { module = "com.varabyte.kobweb:kobweb-core ", version.ref = "kobweb" }
9 | kobweb-silk-core = { module = "com.varabyte.kobweb:kobweb-silk", version.ref = "kobweb" }
10 | kobweb-silk-icons-fa = { module = "com.varabyte.kobweb:kobweb-silk-icons-fa", version.ref = "kobweb" }
11 | kobwebx-markdown = { module = "com.varabyte.kobwebx:kobwebx-markdown", version.ref = "kobweb" }
12 |
13 | [plugins]
14 | jetbrains-compose = { id = "org.jetbrains.compose", version.ref = "jetbrains-compose" }
15 | kobweb-application = { id = "com.varabyte.kobweb.application", version.ref = "kobweb" }
16 | kobwebx-markdown = { id = "com.varabyte.kobwebx.markdown", version.ref = "kobweb" }
17 | kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
--------------------------------------------------------------------------------
/site/.kobweb/site/vs.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Visual Studio-like style based on original C# coloring by Jason Diamond
4 |
5 | */
6 | .hljs {
7 | background: white;
8 | color: black;
9 | }
10 |
11 | .hljs-comment,
12 | .hljs-quote,
13 | .hljs-variable {
14 | color: #008000;
15 | }
16 |
17 | .hljs-keyword,
18 | .hljs-selector-tag,
19 | .hljs-built_in,
20 | .hljs-name,
21 | .hljs-tag {
22 | color: #00f;
23 | }
24 |
25 | .hljs-string,
26 | .hljs-title,
27 | .hljs-section,
28 | .hljs-attribute,
29 | .hljs-literal,
30 | .hljs-template-tag,
31 | .hljs-template-variable,
32 | .hljs-type,
33 | .hljs-addition {
34 | color: #a31515;
35 | }
36 |
37 | .hljs-deletion,
38 | .hljs-selector-attr,
39 | .hljs-selector-pseudo,
40 | .hljs-meta {
41 | color: #2b91af;
42 | }
43 |
44 | .hljs-doctag {
45 | color: #808080;
46 | }
47 |
48 | .hljs-attr {
49 | color: #f00;
50 | }
51 |
52 | .hljs-symbol,
53 | .hljs-bullet,
54 | .hljs-link {
55 | color: #00b0e8;
56 | }
57 |
58 |
59 | .hljs-emphasis {
60 | font-style: italic;
61 | }
62 |
63 | .hljs-strong {
64 | font-weight: bold;
65 | }
66 |
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/vs.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Visual Studio-like style based on original C# coloring by Jason Diamond
4 |
5 | */
6 | .hljs {
7 | background: white;
8 | color: black;
9 | }
10 |
11 | .hljs-comment,
12 | .hljs-quote,
13 | .hljs-variable {
14 | color: #008000;
15 | }
16 |
17 | .hljs-keyword,
18 | .hljs-selector-tag,
19 | .hljs-built_in,
20 | .hljs-name,
21 | .hljs-tag {
22 | color: #00f;
23 | }
24 |
25 | .hljs-string,
26 | .hljs-title,
27 | .hljs-section,
28 | .hljs-attribute,
29 | .hljs-literal,
30 | .hljs-template-tag,
31 | .hljs-template-variable,
32 | .hljs-type,
33 | .hljs-addition {
34 | color: #a31515;
35 | }
36 |
37 | .hljs-deletion,
38 | .hljs-selector-attr,
39 | .hljs-selector-pseudo,
40 | .hljs-meta {
41 | color: #2b91af;
42 | }
43 |
44 | .hljs-doctag {
45 | color: #808080;
46 | }
47 |
48 | .hljs-attr {
49 | color: #f00;
50 | }
51 |
52 | .hljs-symbol,
53 | .hljs-bullet,
54 | .hljs-link {
55 | color: #00b0e8;
56 | }
57 |
58 |
59 | .hljs-emphasis {
60 | font-style: italic;
61 | }
62 |
63 | .hljs-strong {
64 | font-weight: bold;
65 | }
66 |
--------------------------------------------------------------------------------
/site/.kobweb/site/lightfair.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Lightfair style (c) Tristian Kelly
4 |
5 | */
6 |
7 | .hljs {
8 | color: #444;
9 | background: #fff;
10 | }
11 |
12 | .hljs-name {
13 | color:#01a3a3;
14 | }
15 |
16 | .hljs-tag,.hljs-meta {
17 | color:#778899;
18 | }
19 |
20 | .hljs-subst {
21 | /* default */
22 | }
23 |
24 | .hljs-comment {
25 | color: #888888
26 | }
27 |
28 | .hljs-keyword,
29 | .hljs-attribute,
30 | .hljs-selector-tag,
31 | .hljs-meta .hljs-keyword,
32 |
33 | .hljs-doctag,
34 | .hljs-name {
35 | font-weight: bold
36 | }
37 |
38 | .hljs-type,
39 | .hljs-string,
40 | .hljs-number,
41 | .hljs-selector-id,
42 | .hljs-selector-class,
43 | .hljs-quote,
44 | .hljs-template-tag,
45 | .hljs-deletion {
46 | color: #4286f4
47 | }
48 |
49 | .hljs-title,
50 | .hljs-section {
51 | color: #4286f4;
52 | font-weight: bold
53 | }
54 |
55 | .hljs-regexp,
56 | .hljs-symbol,
57 | .hljs-variable,
58 | .hljs-template-variable,
59 | .hljs-link,
60 | .hljs-selector-attr,
61 | .hljs-selector-pseudo {
62 | color: #BC6060
63 | }
64 |
65 | .hljs-literal {
66 | color: #62bcbc
67 | }
68 |
69 | .hljs-built_in,
70 | .hljs-bullet,
71 | .hljs-code,
72 | .hljs-addition {
73 | color: #25c6c6
74 | }
75 |
76 | .hljs-meta .hljs-string {
77 | color: #4d99bf
78 | }
79 |
80 | .hljs-emphasis {
81 | font-style: italic
82 | }
83 |
84 | .hljs-strong {
85 | font-weight: bold
86 | }
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/lightfair.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Lightfair style (c) Tristian Kelly
4 |
5 | */
6 |
7 | .hljs {
8 | color: #444;
9 | background: #fff;
10 | }
11 |
12 | .hljs-name {
13 | color:#01a3a3;
14 | }
15 |
16 | .hljs-tag,.hljs-meta {
17 | color:#778899;
18 | }
19 |
20 | .hljs-subst {
21 | /* default */
22 | }
23 |
24 | .hljs-comment {
25 | color: #888888
26 | }
27 |
28 | .hljs-keyword,
29 | .hljs-attribute,
30 | .hljs-selector-tag,
31 | .hljs-meta .hljs-keyword,
32 |
33 | .hljs-doctag,
34 | .hljs-name {
35 | font-weight: bold
36 | }
37 |
38 | .hljs-type,
39 | .hljs-string,
40 | .hljs-number,
41 | .hljs-selector-id,
42 | .hljs-selector-class,
43 | .hljs-quote,
44 | .hljs-template-tag,
45 | .hljs-deletion {
46 | color: #4286f4
47 | }
48 |
49 | .hljs-title,
50 | .hljs-section {
51 | color: #4286f4;
52 | font-weight: bold
53 | }
54 |
55 | .hljs-regexp,
56 | .hljs-symbol,
57 | .hljs-variable,
58 | .hljs-template-variable,
59 | .hljs-link,
60 | .hljs-selector-attr,
61 | .hljs-selector-pseudo {
62 | color: #BC6060
63 | }
64 |
65 | .hljs-literal {
66 | color: #62bcbc
67 | }
68 |
69 | .hljs-built_in,
70 | .hljs-bullet,
71 | .hljs-code,
72 | .hljs-addition {
73 | color: #25c6c6
74 | }
75 |
76 | .hljs-meta .hljs-string {
77 | color: #4d99bf
78 | }
79 |
80 | .hljs-emphasis {
81 | font-style: italic
82 | }
83 |
84 | .hljs-strong {
85 | font-weight: bold
86 | }
--------------------------------------------------------------------------------
/site/src/jsMain/kotlin/com/stevdza/san/pages/Index.kt:
--------------------------------------------------------------------------------
1 | package com.stevdza.san.pages
2 |
3 | import androidx.compose.runtime.Composable
4 | import com.stevdza.san.components.Editor
5 | import com.stevdza.san.components.Footer
6 | import com.stevdza.san.util.Res
7 | import com.varabyte.kobweb.compose.foundation.layout.Arrangement
8 | import com.varabyte.kobweb.compose.foundation.layout.Box
9 | import com.varabyte.kobweb.compose.foundation.layout.Column
10 | import com.varabyte.kobweb.compose.ui.Alignment
11 | import com.varabyte.kobweb.compose.ui.Modifier
12 | import com.varabyte.kobweb.compose.ui.modifiers.*
13 | import com.varabyte.kobweb.core.Page
14 | import com.varabyte.kobweb.silk.components.graphics.Image
15 | import org.jetbrains.compose.web.css.percent
16 | import org.jetbrains.compose.web.css.px
17 |
18 | @Page
19 | @Composable
20 | fun HomePage() {
21 | Box(
22 | modifier = Modifier
23 | .fillMaxWidth()
24 | .minHeight(100.percent)
25 | ) {
26 | Column(
27 | modifier = Modifier.fillMaxSize(),
28 | verticalArrangement = Arrangement.Center,
29 | horizontalAlignment = Alignment.CenterHorizontally
30 | ) {
31 | Image(src = Res.Image.logo, modifier = Modifier.size(200.px))
32 | Editor()
33 | }
34 | Footer(
35 | modifier = Modifier
36 | .gridRowStart(2)
37 | .gridRowEnd(6)
38 | )
39 | }
40 | }
--------------------------------------------------------------------------------
/site/src/jsMain/kotlin/com/stevdza/san/components/Footer.kt:
--------------------------------------------------------------------------------
1 | package com.stevdza.san.components
2 |
3 | import androidx.compose.runtime.Composable
4 | import com.stevdza.san.model.EditorTheme
5 | import com.varabyte.kobweb.compose.foundation.layout.Arrangement
6 | import com.varabyte.kobweb.compose.foundation.layout.Row
7 | import com.varabyte.kobweb.compose.ui.Alignment
8 | import com.varabyte.kobweb.compose.ui.Modifier
9 | import com.varabyte.kobweb.compose.ui.modifiers.*
10 | import com.varabyte.kobweb.navigation.OpenLinkStrategy
11 | import com.varabyte.kobweb.silk.components.navigation.Link
12 | import com.varabyte.kobweb.silk.components.style.*
13 | import org.jetbrains.compose.web.css.cssRem
14 | import org.jetbrains.compose.web.css.px
15 | import org.jetbrains.compose.web.dom.Text
16 |
17 | val FooterStyle by ComponentStyle.base {
18 | Modifier
19 | .fillMaxWidth()
20 | .margin(topBottom = 20.px)
21 | .fontSize(14.px)
22 | }
23 |
24 | val LinkStyle by ComponentStyle {
25 | anyLink {
26 | Modifier.color(EditorTheme.RoyalBlue.color)
27 | }
28 | }
29 |
30 | @Composable
31 | fun Footer(modifier: Modifier = Modifier) {
32 | Row(
33 | FooterStyle.toModifier().then(modifier),
34 | verticalAlignment = Alignment.CenterVertically,
35 | horizontalArrangement = Arrangement.Center
36 | ) {
37 | Text("Developed by")
38 | Link(
39 | modifier = LinkStyle.toModifier().margin(left = 6.px),
40 | path = "https://www.youtube.com/stevdza_san",
41 | text = "Stevdza-San",
42 | openExternalLinksStrategy = OpenLinkStrategy.IN_NEW_TAB
43 | )
44 | }
45 | }
--------------------------------------------------------------------------------
/site/.kobweb/site/intellij-light.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Intellij-light style (c) Pegasis
4 |
5 | */
6 |
7 | .hljs {
8 | color: #000;
9 | background: #fff;
10 | }
11 |
12 | .hljs-subst,
13 | .hljs-title {
14 | font-weight: normal;
15 | color: #000;
16 | }
17 |
18 | .hljs-title.function_ {
19 | color: #7A7A43;
20 | }
21 |
22 | .hljs-code,
23 | .hljs-comment,
24 | .hljs-quote {
25 | color: #8C8C8C;
26 | font-style: italic;
27 | }
28 |
29 | .hljs-meta {
30 | color: #9E880D;
31 | }
32 |
33 | .hljs-section {
34 | color: #871094;
35 | }
36 |
37 | .hljs-variable.language_,
38 | .hljs-symbol,
39 | .hljs-selector-class,
40 | .hljs-selector-id,
41 | .hljs-selector-tag,
42 | .hljs-template-tag,
43 | .hljs-selector-attr,
44 | .hljs-selector-pseudo,
45 | .hljs-keyword,
46 | .hljs-meta .hljs-keyword,
47 | .hljs-literal,
48 | .hljs-name,
49 | .hljs-built_in,
50 | .hljs-type {
51 | color: #0033B3;
52 | }
53 |
54 | .hljs-property,
55 | .hljs-attr {
56 | color: #871094;
57 | }
58 |
59 | .hljs-attribute {
60 | color: #174AD4;
61 | }
62 |
63 | .hljs-number {
64 | color: #1750EB;
65 | }
66 |
67 | .hljs-regexp {
68 | color: #264EFF;
69 | }
70 |
71 | .hljs-link {
72 | text-decoration: underline;
73 | color: #006DCC;
74 | }
75 |
76 | .hljs-meta .hljs-string,
77 | .hljs-string {
78 | color: #067D17;
79 | }
80 |
81 | .hljs-char.escape_ {
82 | color: #0037A6;
83 | }
84 |
85 | .hljs-doctag {
86 | text-decoration: underline;
87 | }
88 |
89 | .hljs-template-variable {
90 | color: #248F8F;
91 | }
92 |
93 | .hljs-addition {
94 | background: #BEE6BE;
95 | }
96 |
97 | .hljs-deletion {
98 | background: #D6D6D6;
99 | }
100 |
101 | .hljs-emphasis {
102 | font-style: italic;
103 | }
104 |
105 | .hljs-strong {
106 | font-weight: bold;
107 | }
108 |
109 | .hljs-variable,
110 | .hljs-operator,
111 | .hljs-punctuation,
112 | .hljs-title.class_.inherited__,
113 | .hljs-title.class_,
114 | .hljs-params,
115 | .hljs-bullet,
116 | .hljs-formula,
117 | .hljs-tag {
118 | /* purposely ignored */
119 | }
120 |
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/intellij-light.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Intellij-light style (c) Pegasis
4 |
5 | */
6 |
7 | .hljs {
8 | color: #000;
9 | background: #fff;
10 | }
11 |
12 | .hljs-subst,
13 | .hljs-title {
14 | font-weight: normal;
15 | color: #000;
16 | }
17 |
18 | .hljs-title.function_ {
19 | color: #7A7A43;
20 | }
21 |
22 | .hljs-code,
23 | .hljs-comment,
24 | .hljs-quote {
25 | color: #8C8C8C;
26 | font-style: italic;
27 | }
28 |
29 | .hljs-meta {
30 | color: #9E880D;
31 | }
32 |
33 | .hljs-section {
34 | color: #871094;
35 | }
36 |
37 | .hljs-variable.language_,
38 | .hljs-symbol,
39 | .hljs-selector-class,
40 | .hljs-selector-id,
41 | .hljs-selector-tag,
42 | .hljs-template-tag,
43 | .hljs-selector-attr,
44 | .hljs-selector-pseudo,
45 | .hljs-keyword,
46 | .hljs-meta .hljs-keyword,
47 | .hljs-literal,
48 | .hljs-name,
49 | .hljs-built_in,
50 | .hljs-type {
51 | color: #0033B3;
52 | }
53 |
54 | .hljs-property,
55 | .hljs-attr {
56 | color: #871094;
57 | }
58 |
59 | .hljs-attribute {
60 | color: #174AD4;
61 | }
62 |
63 | .hljs-number {
64 | color: #1750EB;
65 | }
66 |
67 | .hljs-regexp {
68 | color: #264EFF;
69 | }
70 |
71 | .hljs-link {
72 | text-decoration: underline;
73 | color: #006DCC;
74 | }
75 |
76 | .hljs-meta .hljs-string,
77 | .hljs-string {
78 | color: #067D17;
79 | }
80 |
81 | .hljs-char.escape_ {
82 | color: #0037A6;
83 | }
84 |
85 | .hljs-doctag {
86 | text-decoration: underline;
87 | }
88 |
89 | .hljs-template-variable {
90 | color: #248F8F;
91 | }
92 |
93 | .hljs-addition {
94 | background: #BEE6BE;
95 | }
96 |
97 | .hljs-deletion {
98 | background: #D6D6D6;
99 | }
100 |
101 | .hljs-emphasis {
102 | font-style: italic;
103 | }
104 |
105 | .hljs-strong {
106 | font-weight: bold;
107 | }
108 |
109 | .hljs-variable,
110 | .hljs-operator,
111 | .hljs-punctuation,
112 | .hljs-title.class_.inherited__,
113 | .hljs-title.class_,
114 | .hljs-params,
115 | .hljs-bullet,
116 | .hljs-formula,
117 | .hljs-tag {
118 | /* purposely ignored */
119 | }
120 |
--------------------------------------------------------------------------------
/site/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import com.varabyte.kobweb.gradle.application.util.configAsKobwebApplication
2 | import kotlinx.html.link
3 | import kotlinx.html.script
4 |
5 | @Suppress("DSL_SCOPE_VIOLATION")
6 | plugins {
7 | alias(libs.plugins.kotlin.multiplatform)
8 | alias(libs.plugins.jetbrains.compose)
9 | alias(libs.plugins.kobweb.application)
10 | alias(libs.plugins.kobwebx.markdown)
11 | }
12 |
13 | group = "com.stevdza.san"
14 | version = "1.0-SNAPSHOT"
15 |
16 | kobweb {
17 | app {
18 | index {
19 | description.set(
20 | "Web app that allows you to paste, apply colors and export your code as a beautiful image," +
21 | " that you can later share with everyone on social media!"
22 | )
23 |
24 | head.add {
25 | script {
26 | async = true
27 | src = "https://www.googletagmanager.com/gtag/js?id=G-M6NQ3C6B4S"
28 | }
29 | script {
30 | src = "gtag.js"
31 | }
32 | script {
33 | src = "dom-to-image.js"
34 | }
35 | script {
36 | src = "FileSaver.js"
37 | }
38 | script {
39 | src = "highlight.min.js"
40 | }
41 | script {
42 | src = "https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
43 | }
44 | link {
45 | rel = "stylesheet"
46 | href = "https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
47 | }
48 | link {
49 | rel = "stylesheet"
50 | href = "lightfair.css"
51 | }
52 | }
53 | }
54 | }
55 | }
56 |
57 | kotlin {
58 | configAsKobwebApplication("san", includeServer = true)
59 | tasks.withType {
60 | kotlinOptions.jvmTarget = "11"
61 | }
62 |
63 | sourceSets {
64 | val commonMain by getting {
65 | dependencies {
66 | implementation(compose.runtime)
67 | }
68 | }
69 |
70 | val jsMain by getting {
71 | dependencies {
72 | implementation(compose.web.core)
73 | implementation(libs.kobweb.core)
74 | implementation(libs.kobweb.silk.core)
75 | implementation(libs.kobweb.silk.icons.fa)
76 | implementation(libs.kobwebx.markdown)
77 | }
78 | }
79 | val jvmMain by getting {
80 | dependencies {
81 | implementation(libs.kobweb.api)
82 | }
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/site/.kobweb/site/cupertino.css:
--------------------------------------------------------------------------------
1 | /*!
2 | Theme: Cupertino
3 | Author: Defman21
4 | License: ~ MIT (or more permissive) [via base16-schemes-source]
5 | Maintainer: @highlightjs/core-team
6 | Version: 2021.09.0
7 | */
8 |
9 | /*
10 | WARNING: DO NOT EDIT THIS FILE DIRECTLY.
11 |
12 | This theme file was auto-generated from the Base16 scheme cupertino
13 | by the Highlight.js Base16 template builder.
14 |
15 | - https://github.com/highlightjs/base16-highlightjs
16 | */
17 |
18 | /*
19 | base00 #ffffff Default Background
20 | base01 #c0c0c0 Lighter Background (Used for status bars, line number and folding marks)
21 | base02 #c0c0c0 Selection Background
22 | base03 #808080 Comments, Invisibles, Line Highlighting
23 | base04 #808080 Dark Foreground (Used for status bars)
24 | base05 #404040 Default Foreground, Caret, Delimiters, Operators
25 | base06 #404040 Light Foreground (Not often used)
26 | base07 #5e5e5e Light Background (Not often used)
27 | base08 #c41a15 Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
28 | base09 #eb8500 Integers, Boolean, Constants, XML Attributes, Markup Link Url
29 | base0A #826b28 Classes, Markup Bold, Search Text Background
30 | base0B #007400 Strings, Inherited Class, Markup Code, Diff Inserted
31 | base0C #318495 Support, Regular Expressions, Escape Characters, Markup Quotes
32 | base0D #0000ff Functions, Methods, Attribute IDs, Headings
33 | base0E #a90d91 Keywords, Storage, Selector, Markup Italic, Diff Changed
34 | base0F #826b28 Deprecated, Opening/Closing Embedded Language Tags, e.g.
35 | */
36 |
37 | pre code.hljs {
38 | display: block;
39 | overflow-x: auto;
40 | padding: 1em;
41 | }
42 |
43 | code.hljs {
44 | padding: 3px 5px;
45 | }
46 |
47 | .hljs {
48 | color: #404040;
49 | background: #ffffff;
50 | }
51 |
52 | .hljs::selection,
53 | .hljs ::selection {
54 | background-color: #c0c0c0;
55 | color: #404040;
56 | }
57 |
58 |
59 | /* purposely do not highlight these things */
60 | .hljs-formula,
61 | .hljs-params,
62 | .hljs-property
63 | {}
64 |
65 | /* base03 - #808080 - Comments, Invisibles, Line Highlighting */
66 | .hljs-comment {
67 | color: #808080;
68 | }
69 |
70 | /* base04 - #808080 - Dark Foreground (Used for status bars) */
71 | .hljs-tag {
72 | color: #808080;
73 | }
74 |
75 | /* base05 - #404040 - Default Foreground, Caret, Delimiters, Operators */
76 | .hljs-subst,
77 | .hljs-punctuation,
78 | .hljs-operator {
79 | color: #404040;
80 | }
81 |
82 | .hljs-operator {
83 | opacity: 0.7;
84 | }
85 |
86 | /* base08 - Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted */
87 | .hljs-bullet,
88 | .hljs-variable,
89 | .hljs-template-variable,
90 | .hljs-selector-tag,
91 | .hljs-name,
92 | .hljs-deletion {
93 | color: #c41a15;
94 | }
95 |
96 | /* base09 - Integers, Boolean, Constants, XML Attributes, Markup Link Url */
97 | .hljs-symbol,
98 | .hljs-number,
99 | .hljs-link,
100 | .hljs-attr,
101 | .hljs-variable.constant_,
102 | .hljs-literal {
103 | color: #eb8500;
104 | }
105 |
106 | /* base0A - Classes, Markup Bold, Search Text Background */
107 | .hljs-title,
108 | .hljs-class .hljs-title,
109 | .hljs-title.class_
110 | {
111 | color: #826b28;
112 | }
113 |
114 | .hljs-strong {
115 | font-weight:bold;
116 | color: #826b28;
117 | }
118 |
119 | /* base0B - Strings, Inherited Class, Markup Code, Diff Inserted */
120 | .hljs-code,
121 | .hljs-addition,
122 | .hljs-title.class_.inherited__,
123 | .hljs-string {
124 | color: #007400;
125 | }
126 |
127 | /* base0C - Support, Regular Expressions, Escape Characters, Markup Quotes */
128 | .hljs-built_in,
129 | .hljs-doctag, /* guessing */
130 | .hljs-quote,
131 | .hljs-keyword.hljs-atrule,
132 | .hljs-regexp {
133 | color: #318495;
134 | }
135 |
136 | /* base0D - Functions, Methods, Attribute IDs, Headings */
137 | .hljs-function .hljs-title,
138 | .hljs-attribute,
139 | .ruby .hljs-property,
140 | .hljs-title.function_,
141 | .hljs-section {
142 | color: #0000ff;
143 | }
144 |
145 | /* base0E - Keywords, Storage, Selector, Markup Italic, Diff Changed */
146 | .hljs-type,
147 | /* .hljs-selector-id, */
148 | /* .hljs-selector-class, */
149 | /* .hljs-selector-attr, */
150 | /* .hljs-selector-pseudo, */
151 | .hljs-template-tag,
152 | .diff .hljs-meta,
153 | .hljs-keyword {
154 | color: #a90d91;
155 | }
156 | .hljs-emphasis {
157 | color: #a90d91;
158 | font-style: italic;
159 | }
160 |
161 | /* base0F - Deprecated, Opening/Closing Embedded Language Tags, e.g. */
162 | .hljs-meta,
163 | /*
164 | prevent top level .keyword and .string scopes
165 | from leaking into meta by accident
166 | */
167 | .hljs-meta .hljs-keyword,
168 | .hljs-meta .hljs-string
169 | {
170 | color: #826b28;
171 | }
172 |
173 | .hljs-meta .hljs-keyword,
174 | /* for v10 compatible themes */
175 | .hljs-meta-keyword {
176 | font-weight: bold;
177 | }
178 |
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/cupertino.css:
--------------------------------------------------------------------------------
1 | /*!
2 | Theme: Cupertino
3 | Author: Defman21
4 | License: ~ MIT (or more permissive) [via base16-schemes-source]
5 | Maintainer: @highlightjs/core-team
6 | Version: 2021.09.0
7 | */
8 |
9 | /*
10 | WARNING: DO NOT EDIT THIS FILE DIRECTLY.
11 |
12 | This theme file was auto-generated from the Base16 scheme cupertino
13 | by the Highlight.js Base16 template builder.
14 |
15 | - https://github.com/highlightjs/base16-highlightjs
16 | */
17 |
18 | /*
19 | base00 #ffffff Default Background
20 | base01 #c0c0c0 Lighter Background (Used for status bars, line number and folding marks)
21 | base02 #c0c0c0 Selection Background
22 | base03 #808080 Comments, Invisibles, Line Highlighting
23 | base04 #808080 Dark Foreground (Used for status bars)
24 | base05 #404040 Default Foreground, Caret, Delimiters, Operators
25 | base06 #404040 Light Foreground (Not often used)
26 | base07 #5e5e5e Light Background (Not often used)
27 | base08 #c41a15 Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
28 | base09 #eb8500 Integers, Boolean, Constants, XML Attributes, Markup Link Url
29 | base0A #826b28 Classes, Markup Bold, Search Text Background
30 | base0B #007400 Strings, Inherited Class, Markup Code, Diff Inserted
31 | base0C #318495 Support, Regular Expressions, Escape Characters, Markup Quotes
32 | base0D #0000ff Functions, Methods, Attribute IDs, Headings
33 | base0E #a90d91 Keywords, Storage, Selector, Markup Italic, Diff Changed
34 | base0F #826b28 Deprecated, Opening/Closing Embedded Language Tags, e.g.
35 | */
36 |
37 | pre code.hljs {
38 | display: block;
39 | overflow-x: auto;
40 | padding: 1em;
41 | }
42 |
43 | code.hljs {
44 | padding: 3px 5px;
45 | }
46 |
47 | .hljs {
48 | color: #404040;
49 | background: #ffffff;
50 | }
51 |
52 | .hljs::selection,
53 | .hljs ::selection {
54 | background-color: #c0c0c0;
55 | color: #404040;
56 | }
57 |
58 |
59 | /* purposely do not highlight these things */
60 | .hljs-formula,
61 | .hljs-params,
62 | .hljs-property
63 | {}
64 |
65 | /* base03 - #808080 - Comments, Invisibles, Line Highlighting */
66 | .hljs-comment {
67 | color: #808080;
68 | }
69 |
70 | /* base04 - #808080 - Dark Foreground (Used for status bars) */
71 | .hljs-tag {
72 | color: #808080;
73 | }
74 |
75 | /* base05 - #404040 - Default Foreground, Caret, Delimiters, Operators */
76 | .hljs-subst,
77 | .hljs-punctuation,
78 | .hljs-operator {
79 | color: #404040;
80 | }
81 |
82 | .hljs-operator {
83 | opacity: 0.7;
84 | }
85 |
86 | /* base08 - Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted */
87 | .hljs-bullet,
88 | .hljs-variable,
89 | .hljs-template-variable,
90 | .hljs-selector-tag,
91 | .hljs-name,
92 | .hljs-deletion {
93 | color: #c41a15;
94 | }
95 |
96 | /* base09 - Integers, Boolean, Constants, XML Attributes, Markup Link Url */
97 | .hljs-symbol,
98 | .hljs-number,
99 | .hljs-link,
100 | .hljs-attr,
101 | .hljs-variable.constant_,
102 | .hljs-literal {
103 | color: #eb8500;
104 | }
105 |
106 | /* base0A - Classes, Markup Bold, Search Text Background */
107 | .hljs-title,
108 | .hljs-class .hljs-title,
109 | .hljs-title.class_
110 | {
111 | color: #826b28;
112 | }
113 |
114 | .hljs-strong {
115 | font-weight:bold;
116 | color: #826b28;
117 | }
118 |
119 | /* base0B - Strings, Inherited Class, Markup Code, Diff Inserted */
120 | .hljs-code,
121 | .hljs-addition,
122 | .hljs-title.class_.inherited__,
123 | .hljs-string {
124 | color: #007400;
125 | }
126 |
127 | /* base0C - Support, Regular Expressions, Escape Characters, Markup Quotes */
128 | .hljs-built_in,
129 | .hljs-doctag, /* guessing */
130 | .hljs-quote,
131 | .hljs-keyword.hljs-atrule,
132 | .hljs-regexp {
133 | color: #318495;
134 | }
135 |
136 | /* base0D - Functions, Methods, Attribute IDs, Headings */
137 | .hljs-function .hljs-title,
138 | .hljs-attribute,
139 | .ruby .hljs-property,
140 | .hljs-title.function_,
141 | .hljs-section {
142 | color: #0000ff;
143 | }
144 |
145 | /* base0E - Keywords, Storage, Selector, Markup Italic, Diff Changed */
146 | .hljs-type,
147 | /* .hljs-selector-id, */
148 | /* .hljs-selector-class, */
149 | /* .hljs-selector-attr, */
150 | /* .hljs-selector-pseudo, */
151 | .hljs-template-tag,
152 | .diff .hljs-meta,
153 | .hljs-keyword {
154 | color: #a90d91;
155 | }
156 | .hljs-emphasis {
157 | color: #a90d91;
158 | font-style: italic;
159 | }
160 |
161 | /* base0F - Deprecated, Opening/Closing Embedded Language Tags, e.g. */
162 | .hljs-meta,
163 | /*
164 | prevent top level .keyword and .string scopes
165 | from leaking into meta by accident
166 | */
167 | .hljs-meta .hljs-keyword,
168 | .hljs-meta .hljs-string
169 | {
170 | color: #826b28;
171 | }
172 |
173 | .hljs-meta .hljs-keyword,
174 | /* for v10 compatible themes */
175 | .hljs-meta-keyword {
176 | font-weight: bold;
177 | }
178 |
--------------------------------------------------------------------------------
/site/.kobweb/site/google-light.css:
--------------------------------------------------------------------------------
1 | /*!
2 | Theme: Google Light
3 | Author: Seth Wright (http://sethawright.com)
4 | License: ~ MIT (or more permissive) [via base16-schemes-source]
5 | Maintainer: @highlightjs/core-team
6 | Version: 2021.09.0
7 | */
8 |
9 | /*
10 | WARNING: DO NOT EDIT THIS FILE DIRECTLY.
11 |
12 | This theme file was auto-generated from the Base16 scheme google-light
13 | by the Highlight.js Base16 template builder.
14 |
15 | - https://github.com/highlightjs/base16-highlightjs
16 | */
17 |
18 | /*
19 | base00 #ffffff Default Background
20 | base01 #e0e0e0 Lighter Background (Used for status bars, line number and folding marks)
21 | base02 #c5c8c6 Selection Background
22 | base03 #b4b7b4 Comments, Invisibles, Line Highlighting
23 | base04 #969896 Dark Foreground (Used for status bars)
24 | base05 #373b41 Default Foreground, Caret, Delimiters, Operators
25 | base06 #282a2e Light Foreground (Not often used)
26 | base07 #1d1f21 Light Background (Not often used)
27 | base08 #CC342B Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
28 | base09 #F96A38 Integers, Boolean, Constants, XML Attributes, Markup Link Url
29 | base0A #FBA922 Classes, Markup Bold, Search Text Background
30 | base0B #198844 Strings, Inherited Class, Markup Code, Diff Inserted
31 | base0C #3971ED Support, Regular Expressions, Escape Characters, Markup Quotes
32 | base0D #3971ED Functions, Methods, Attribute IDs, Headings
33 | base0E #A36AC7 Keywords, Storage, Selector, Markup Italic, Diff Changed
34 | base0F #3971ED Deprecated, Opening/Closing Embedded Language Tags, e.g.
35 | */
36 |
37 | pre code.hljs {
38 | display: block;
39 | overflow-x: auto;
40 | padding: 1em;
41 | }
42 |
43 | code.hljs {
44 | padding: 3px 5px;
45 | }
46 |
47 | .hljs {
48 | color: #373b41;
49 | background: #ffffff;
50 | }
51 |
52 | .hljs::selection,
53 | .hljs ::selection {
54 | background-color: #c5c8c6;
55 | color: #373b41;
56 | }
57 |
58 |
59 | /* purposely do not highlight these things */
60 | .hljs-formula,
61 | .hljs-params,
62 | .hljs-property
63 | {}
64 |
65 | /* base03 - #b4b7b4 - Comments, Invisibles, Line Highlighting */
66 | .hljs-comment {
67 | color: #b4b7b4;
68 | }
69 |
70 | /* base04 - #969896 - Dark Foreground (Used for status bars) */
71 | .hljs-tag {
72 | color: #969896;
73 | }
74 |
75 | /* base05 - #373b41 - Default Foreground, Caret, Delimiters, Operators */
76 | .hljs-subst,
77 | .hljs-punctuation,
78 | .hljs-operator {
79 | color: #373b41;
80 | }
81 |
82 | .hljs-operator {
83 | opacity: 0.7;
84 | }
85 |
86 | /* base08 - Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted */
87 | .hljs-bullet,
88 | .hljs-variable,
89 | .hljs-template-variable,
90 | .hljs-selector-tag,
91 | .hljs-name,
92 | .hljs-deletion {
93 | color: #CC342B;
94 | }
95 |
96 | /* base09 - Integers, Boolean, Constants, XML Attributes, Markup Link Url */
97 | .hljs-symbol,
98 | .hljs-number,
99 | .hljs-link,
100 | .hljs-attr,
101 | .hljs-variable.constant_,
102 | .hljs-literal {
103 | color: #F96A38;
104 | }
105 |
106 | /* base0A - Classes, Markup Bold, Search Text Background */
107 | .hljs-title,
108 | .hljs-class .hljs-title,
109 | .hljs-title.class_
110 | {
111 | color: #FBA922;
112 | }
113 |
114 | .hljs-strong {
115 | font-weight:bold;
116 | color: #FBA922;
117 | }
118 |
119 | /* base0B - Strings, Inherited Class, Markup Code, Diff Inserted */
120 | .hljs-code,
121 | .hljs-addition,
122 | .hljs-title.class_.inherited__,
123 | .hljs-string {
124 | color: #198844;
125 | }
126 |
127 | /* base0C - Support, Regular Expressions, Escape Characters, Markup Quotes */
128 | .hljs-built_in,
129 | .hljs-doctag, /* guessing */
130 | .hljs-quote,
131 | .hljs-keyword.hljs-atrule,
132 | .hljs-regexp {
133 | color: #3971ED;
134 | }
135 |
136 | /* base0D - Functions, Methods, Attribute IDs, Headings */
137 | .hljs-function .hljs-title,
138 | .hljs-attribute,
139 | .ruby .hljs-property,
140 | .hljs-title.function_,
141 | .hljs-section {
142 | color: #3971ED;
143 | }
144 |
145 | /* base0E - Keywords, Storage, Selector, Markup Italic, Diff Changed */
146 | .hljs-type,
147 | /* .hljs-selector-id, */
148 | /* .hljs-selector-class, */
149 | /* .hljs-selector-attr, */
150 | /* .hljs-selector-pseudo, */
151 | .hljs-template-tag,
152 | .diff .hljs-meta,
153 | .hljs-keyword {
154 | color: #A36AC7;
155 | }
156 | .hljs-emphasis {
157 | color: #A36AC7;
158 | font-style: italic;
159 | }
160 |
161 | /* base0F - Deprecated, Opening/Closing Embedded Language Tags, e.g. */
162 | .hljs-meta,
163 | /*
164 | prevent top level .keyword and .string scopes
165 | from leaking into meta by accident
166 | */
167 | .hljs-meta .hljs-keyword,
168 | .hljs-meta .hljs-string
169 | {
170 | color: #3971ED;
171 | }
172 |
173 | .hljs-meta .hljs-keyword,
174 | /* for v10 compatible themes */
175 | .hljs-meta-keyword {
176 | font-weight: bold;
177 | }
178 |
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/google-light.css:
--------------------------------------------------------------------------------
1 | /*!
2 | Theme: Google Light
3 | Author: Seth Wright (http://sethawright.com)
4 | License: ~ MIT (or more permissive) [via base16-schemes-source]
5 | Maintainer: @highlightjs/core-team
6 | Version: 2021.09.0
7 | */
8 |
9 | /*
10 | WARNING: DO NOT EDIT THIS FILE DIRECTLY.
11 |
12 | This theme file was auto-generated from the Base16 scheme google-light
13 | by the Highlight.js Base16 template builder.
14 |
15 | - https://github.com/highlightjs/base16-highlightjs
16 | */
17 |
18 | /*
19 | base00 #ffffff Default Background
20 | base01 #e0e0e0 Lighter Background (Used for status bars, line number and folding marks)
21 | base02 #c5c8c6 Selection Background
22 | base03 #b4b7b4 Comments, Invisibles, Line Highlighting
23 | base04 #969896 Dark Foreground (Used for status bars)
24 | base05 #373b41 Default Foreground, Caret, Delimiters, Operators
25 | base06 #282a2e Light Foreground (Not often used)
26 | base07 #1d1f21 Light Background (Not often used)
27 | base08 #CC342B Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
28 | base09 #F96A38 Integers, Boolean, Constants, XML Attributes, Markup Link Url
29 | base0A #FBA922 Classes, Markup Bold, Search Text Background
30 | base0B #198844 Strings, Inherited Class, Markup Code, Diff Inserted
31 | base0C #3971ED Support, Regular Expressions, Escape Characters, Markup Quotes
32 | base0D #3971ED Functions, Methods, Attribute IDs, Headings
33 | base0E #A36AC7 Keywords, Storage, Selector, Markup Italic, Diff Changed
34 | base0F #3971ED Deprecated, Opening/Closing Embedded Language Tags, e.g.
35 | */
36 |
37 | pre code.hljs {
38 | display: block;
39 | overflow-x: auto;
40 | padding: 1em;
41 | }
42 |
43 | code.hljs {
44 | padding: 3px 5px;
45 | }
46 |
47 | .hljs {
48 | color: #373b41;
49 | background: #ffffff;
50 | }
51 |
52 | .hljs::selection,
53 | .hljs ::selection {
54 | background-color: #c5c8c6;
55 | color: #373b41;
56 | }
57 |
58 |
59 | /* purposely do not highlight these things */
60 | .hljs-formula,
61 | .hljs-params,
62 | .hljs-property
63 | {}
64 |
65 | /* base03 - #b4b7b4 - Comments, Invisibles, Line Highlighting */
66 | .hljs-comment {
67 | color: #b4b7b4;
68 | }
69 |
70 | /* base04 - #969896 - Dark Foreground (Used for status bars) */
71 | .hljs-tag {
72 | color: #969896;
73 | }
74 |
75 | /* base05 - #373b41 - Default Foreground, Caret, Delimiters, Operators */
76 | .hljs-subst,
77 | .hljs-punctuation,
78 | .hljs-operator {
79 | color: #373b41;
80 | }
81 |
82 | .hljs-operator {
83 | opacity: 0.7;
84 | }
85 |
86 | /* base08 - Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted */
87 | .hljs-bullet,
88 | .hljs-variable,
89 | .hljs-template-variable,
90 | .hljs-selector-tag,
91 | .hljs-name,
92 | .hljs-deletion {
93 | color: #CC342B;
94 | }
95 |
96 | /* base09 - Integers, Boolean, Constants, XML Attributes, Markup Link Url */
97 | .hljs-symbol,
98 | .hljs-number,
99 | .hljs-link,
100 | .hljs-attr,
101 | .hljs-variable.constant_,
102 | .hljs-literal {
103 | color: #F96A38;
104 | }
105 |
106 | /* base0A - Classes, Markup Bold, Search Text Background */
107 | .hljs-title,
108 | .hljs-class .hljs-title,
109 | .hljs-title.class_
110 | {
111 | color: #FBA922;
112 | }
113 |
114 | .hljs-strong {
115 | font-weight:bold;
116 | color: #FBA922;
117 | }
118 |
119 | /* base0B - Strings, Inherited Class, Markup Code, Diff Inserted */
120 | .hljs-code,
121 | .hljs-addition,
122 | .hljs-title.class_.inherited__,
123 | .hljs-string {
124 | color: #198844;
125 | }
126 |
127 | /* base0C - Support, Regular Expressions, Escape Characters, Markup Quotes */
128 | .hljs-built_in,
129 | .hljs-doctag, /* guessing */
130 | .hljs-quote,
131 | .hljs-keyword.hljs-atrule,
132 | .hljs-regexp {
133 | color: #3971ED;
134 | }
135 |
136 | /* base0D - Functions, Methods, Attribute IDs, Headings */
137 | .hljs-function .hljs-title,
138 | .hljs-attribute,
139 | .ruby .hljs-property,
140 | .hljs-title.function_,
141 | .hljs-section {
142 | color: #3971ED;
143 | }
144 |
145 | /* base0E - Keywords, Storage, Selector, Markup Italic, Diff Changed */
146 | .hljs-type,
147 | /* .hljs-selector-id, */
148 | /* .hljs-selector-class, */
149 | /* .hljs-selector-attr, */
150 | /* .hljs-selector-pseudo, */
151 | .hljs-template-tag,
152 | .diff .hljs-meta,
153 | .hljs-keyword {
154 | color: #A36AC7;
155 | }
156 | .hljs-emphasis {
157 | color: #A36AC7;
158 | font-style: italic;
159 | }
160 |
161 | /* base0F - Deprecated, Opening/Closing Embedded Language Tags, e.g. */
162 | .hljs-meta,
163 | /*
164 | prevent top level .keyword and .string scopes
165 | from leaking into meta by accident
166 | */
167 | .hljs-meta .hljs-keyword,
168 | .hljs-meta .hljs-string
169 | {
170 | color: #3971ED;
171 | }
172 |
173 | .hljs-meta .hljs-keyword,
174 | /* for v10 compatible themes */
175 | .hljs-meta-keyword {
176 | font-weight: bold;
177 | }
178 |
--------------------------------------------------------------------------------
/site/src/jsMain/kotlin/com/stevdza/san/components/Editor.kt:
--------------------------------------------------------------------------------
1 | package com.stevdza.san.components
2 |
3 | import androidx.compose.runtime.*
4 | import com.stevdza.san.model.EditorTheme
5 | import com.stevdza.san.model.Theme
6 | import com.stevdza.san.util.Res
7 | import com.varabyte.kobweb.compose.css.Overflow
8 | import com.varabyte.kobweb.compose.foundation.layout.Box
9 | import com.varabyte.kobweb.compose.foundation.layout.Column
10 | import com.varabyte.kobweb.compose.foundation.layout.Row
11 | import com.varabyte.kobweb.compose.ui.Modifier
12 | import com.varabyte.kobweb.compose.ui.graphics.Colors
13 | import com.varabyte.kobweb.compose.ui.modifiers.*
14 | import com.varabyte.kobweb.compose.ui.styleModifier
15 | import com.varabyte.kobweb.compose.ui.toAttrs
16 | import com.varabyte.kobweb.silk.components.layout.Surface
17 | import com.varabyte.kobweb.silk.components.style.breakpoint.Breakpoint
18 | import com.varabyte.kobweb.silk.theme.breakpoint.rememberBreakpoint
19 | import com.varabyte.kobweb.silk.theme.shapes.Circle
20 | import com.varabyte.kobweb.silk.theme.shapes.clip
21 | import kotlinx.browser.document
22 | import org.jetbrains.compose.web.css.*
23 | import org.jetbrains.compose.web.dom.Code
24 | import org.jetbrains.compose.web.dom.Pre
25 | import org.jetbrains.compose.web.dom.Text
26 |
27 | @Composable
28 | fun Editor() {
29 | var padding by remember { mutableStateOf(50) }
30 | var fontSize by remember { mutableStateOf(20) }
31 | var lineHeight by remember { mutableStateOf(20) }
32 | var editorTheme by remember { mutableStateOf(EditorTheme.RoyalBlue) }
33 | val breakpoint by rememberBreakpoint()
34 |
35 | ControlsView(
36 | defaultPadding = padding,
37 | defaultFontSize = fontSize,
38 | defaultLineHeight = lineHeight,
39 | defaultTheme = editorTheme.name,
40 | onPaddingChanged = { value ->
41 | padding = if (value in 10..99)
42 | value else 100
43 | },
44 | onFontSizeChanged = { value ->
45 | fontSize = if (value in 14..29)
46 | value else 30
47 | },
48 | onLineHeightChanged = { value ->
49 | lineHeight = if (value in 16..39)
50 | value else 40
51 | },
52 | onThemeChanged = { editorTheme = it },
53 | )
54 | Column(
55 | modifier = Modifier
56 | .id(Res.Id.editor)
57 | .padding(all = padding.px)
58 | .backgroundColor(editorTheme.color)
59 | ) {
60 | EditorHeader()
61 | EditorBody(
62 | fontSize = fontSize,
63 | lineHeight = lineHeight,
64 | padding = padding,
65 | breakpoint = breakpoint
66 | )
67 | }
68 | }
69 |
70 | @Composable
71 | private fun EditorHeader() {
72 | Surface(
73 | modifier = Modifier
74 | .fillMaxWidth()
75 | .padding(all = 20.px)
76 | .backgroundColor(Colors.White)
77 | .borderRadius(
78 | topLeft = 6.px,
79 | topRight = 6.px,
80 | bottomLeft = 0.px,
81 | bottomRight = 0.px
82 | )
83 | ) {
84 | Row {
85 | repeat(3) { index ->
86 | Box(
87 | modifier = Modifier
88 | .backgroundColor(Theme.values()[index].color)
89 | .size(14.px)
90 | .clip(Circle())
91 | .margin(right = if (index != 2) 10.px else 0.px),
92 | )
93 | }
94 | }
95 | }
96 | }
97 |
98 | @Composable
99 | private fun EditorBody(
100 | fontSize: Int,
101 | lineHeight: Int,
102 | padding: Int,
103 | breakpoint: Breakpoint
104 | ) {
105 | Pre(attrs = Modifier
106 | .width(if (breakpoint <= Breakpoint.MD) 100.vw - padding.px * 2 else 740.px)
107 | .height(350.px)
108 | .minWidth(112.px)
109 | .padding(all = 20.px)
110 | .margin(bottom = 0.px)
111 | .backgroundColor(Colors.White)
112 | .borderRadius(
113 | bottomLeft = 6.px,
114 | bottomRight = 6.px,
115 | topLeft = 0.px,
116 | topRight = 0.px
117 | )
118 | .border(width = 0.px)
119 | .outline(style = LineStyle.None)
120 | .overflow(overflow = Overflow.Hidden)
121 | .styleModifier {
122 | property("resize", "both")
123 | }
124 | .toAttrs()
125 | ) {
126 | Code(attrs = Modifier
127 | .contentEditable(true)
128 | .spellCheck(false)
129 | .classNames("language-kotlin")
130 | .outline(style = LineStyle.None)
131 | .styleModifier {
132 | fontFamily("Roboto", "sans-serif")
133 | fontSize(fontSize.px)
134 | lineHeight(lineHeight.px)
135 | }
136 | .toAttrs {
137 | onPaste {
138 | it.preventDefault()
139 | val text = it.clipboardData?.getData("Text")
140 | if (text != null) {
141 | document.execCommand(
142 | "insertHtml",
143 | false,
144 | "" + text + ""
145 | )
146 | }
147 | }
148 | }
149 | ) {
150 | Text(
151 | """
152 | private val credits = "Kobweb Framework"
153 | """.trimIndent()
154 | )
155 | }
156 | }
157 | }
--------------------------------------------------------------------------------
/site/.kobweb/site/FileSaver.js:
--------------------------------------------------------------------------------
1 | /*
2 | * FileSaver.js
3 | * A saveAs() FileSaver implementation.
4 | *
5 | * By Eli Grey, http://eligrey.com
6 | *
7 | * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
8 | * source : http://purl.eligrey.com/github/FileSaver.js
9 | */
10 |
11 | // The one and only way of getting global scope in all environments
12 | // https://stackoverflow.com/q/3277182/1008999
13 | var _global = typeof window === 'object' && window.window === window
14 | ? window : typeof self === 'object' && self.self === self
15 | ? self : typeof global === 'object' && global.global === global
16 | ? global
17 | : this
18 |
19 | function bom (blob, opts) {
20 | if (typeof opts === 'undefined') opts = { autoBom: false }
21 | else if (typeof opts !== 'object') {
22 | console.warn('Deprecated: Expected third argument to be a object')
23 | opts = { autoBom: !opts }
24 | }
25 |
26 | // prepend BOM for UTF-8 XML and text/* types (including HTML)
27 | // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
28 | if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
29 | return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type })
30 | }
31 | return blob
32 | }
33 |
34 | function download (url, name, opts) {
35 | var xhr = new XMLHttpRequest()
36 | xhr.open('GET', url)
37 | xhr.responseType = 'blob'
38 | xhr.onload = function () {
39 | saveAs(xhr.response, name, opts)
40 | }
41 | xhr.onerror = function () {
42 | console.error('could not download file')
43 | }
44 | xhr.send()
45 | }
46 |
47 | function corsEnabled (url) {
48 | var xhr = new XMLHttpRequest()
49 | // use sync to avoid popup blocker
50 | xhr.open('HEAD', url, false)
51 | try {
52 | xhr.send()
53 | } catch (e) {}
54 | return xhr.status >= 200 && xhr.status <= 299
55 | }
56 |
57 | // `a.click()` doesn't work for all browsers (#465)
58 | function click (node) {
59 | try {
60 | node.dispatchEvent(new MouseEvent('click'))
61 | } catch (e) {
62 | var evt = document.createEvent('MouseEvents')
63 | evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
64 | 20, false, false, false, false, 0, null)
65 | node.dispatchEvent(evt)
66 | }
67 | }
68 |
69 | // Detect WebView inside a native macOS app by ruling out all browsers
70 | // We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
71 | // https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
72 | var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent)
73 |
74 | var saveAs = _global.saveAs || (
75 | // probably in some web worker
76 | (typeof window !== 'object' || window !== _global)
77 | ? function saveAs () { /* noop */ }
78 |
79 | // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
80 | : ('download' in HTMLAnchorElement.prototype && !isMacOSWebView)
81 | ? function saveAs (blob, name, opts) {
82 | var URL = _global.URL || _global.webkitURL
83 | // Namespace is used to prevent conflict w/ Chrome Poper Blocker extension (Issue #561)
84 | var a = document.createElementNS('http://www.w3.org/1999/xhtml', 'a')
85 | name = name || blob.name || 'download'
86 |
87 | a.download = name
88 | a.rel = 'noopener' // tabnabbing
89 |
90 | // TODO: detect chrome extensions & packaged apps
91 | // a.target = '_blank'
92 |
93 | if (typeof blob === 'string') {
94 | // Support regular links
95 | a.href = blob
96 | if (a.origin !== location.origin) {
97 | corsEnabled(a.href)
98 | ? download(blob, name, opts)
99 | : click(a, a.target = '_blank')
100 | } else {
101 | click(a)
102 | }
103 | } else {
104 | // Support blobs
105 | a.href = URL.createObjectURL(blob)
106 | setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s
107 | setTimeout(function () { click(a) }, 0)
108 | }
109 | }
110 |
111 | // Use msSaveOrOpenBlob as a second approach
112 | : 'msSaveOrOpenBlob' in navigator
113 | ? function saveAs (blob, name, opts) {
114 | name = name || blob.name || 'download'
115 |
116 | if (typeof blob === 'string') {
117 | if (corsEnabled(blob)) {
118 | download(blob, name, opts)
119 | } else {
120 | var a = document.createElement('a')
121 | a.href = blob
122 | a.target = '_blank'
123 | setTimeout(function () { click(a) })
124 | }
125 | } else {
126 | navigator.msSaveOrOpenBlob(bom(blob, opts), name)
127 | }
128 | }
129 |
130 | // Fallback to using FileReader and a popup
131 | : function saveAs (blob, name, opts, popup) {
132 | // Open a popup immediately do go around popup blocker
133 | // Mostly only available on user interaction and the fileReader is async so...
134 | popup = popup || open('', '_blank')
135 | if (popup) {
136 | popup.document.title =
137 | popup.document.body.innerText = 'downloading...'
138 | }
139 |
140 | if (typeof blob === 'string') return download(blob, name, opts)
141 |
142 | var force = blob.type === 'application/octet-stream'
143 | var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari
144 | var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
145 |
146 | if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') {
147 | // Safari doesn't allow downloading of blob URLs
148 | var reader = new FileReader()
149 | reader.onloadend = function () {
150 | var url = reader.result
151 | url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
152 | if (popup) popup.location.href = url
153 | else location = url
154 | popup = null // reverse-tabnabbing #460
155 | }
156 | reader.readAsDataURL(blob)
157 | } else {
158 | var URL = _global.URL || _global.webkitURL
159 | var url = URL.createObjectURL(blob)
160 | if (popup) popup.location = url
161 | else location.href = url
162 | popup = null // reverse-tabnabbing #460
163 | setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s
164 | }
165 | }
166 | )
167 |
168 | _global.saveAs = saveAs.saveAs = saveAs
169 |
170 | if (typeof module !== 'undefined') {
171 | module.exports = saveAs;
172 | }
173 |
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/FileSaver.js:
--------------------------------------------------------------------------------
1 | /*
2 | * FileSaver.js
3 | * A saveAs() FileSaver implementation.
4 | *
5 | * By Eli Grey, http://eligrey.com
6 | *
7 | * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
8 | * source : http://purl.eligrey.com/github/FileSaver.js
9 | */
10 |
11 | // The one and only way of getting global scope in all environments
12 | // https://stackoverflow.com/q/3277182/1008999
13 | var _global = typeof window === 'object' && window.window === window
14 | ? window : typeof self === 'object' && self.self === self
15 | ? self : typeof global === 'object' && global.global === global
16 | ? global
17 | : this
18 |
19 | function bom (blob, opts) {
20 | if (typeof opts === 'undefined') opts = { autoBom: false }
21 | else if (typeof opts !== 'object') {
22 | console.warn('Deprecated: Expected third argument to be a object')
23 | opts = { autoBom: !opts }
24 | }
25 |
26 | // prepend BOM for UTF-8 XML and text/* types (including HTML)
27 | // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
28 | if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
29 | return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type })
30 | }
31 | return blob
32 | }
33 |
34 | function download (url, name, opts) {
35 | var xhr = new XMLHttpRequest()
36 | xhr.open('GET', url)
37 | xhr.responseType = 'blob'
38 | xhr.onload = function () {
39 | saveAs(xhr.response, name, opts)
40 | }
41 | xhr.onerror = function () {
42 | console.error('could not download file')
43 | }
44 | xhr.send()
45 | }
46 |
47 | function corsEnabled (url) {
48 | var xhr = new XMLHttpRequest()
49 | // use sync to avoid popup blocker
50 | xhr.open('HEAD', url, false)
51 | try {
52 | xhr.send()
53 | } catch (e) {}
54 | return xhr.status >= 200 && xhr.status <= 299
55 | }
56 |
57 | // `a.click()` doesn't work for all browsers (#465)
58 | function click (node) {
59 | try {
60 | node.dispatchEvent(new MouseEvent('click'))
61 | } catch (e) {
62 | var evt = document.createEvent('MouseEvents')
63 | evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
64 | 20, false, false, false, false, 0, null)
65 | node.dispatchEvent(evt)
66 | }
67 | }
68 |
69 | // Detect WebView inside a native macOS app by ruling out all browsers
70 | // We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
71 | // https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
72 | var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent)
73 |
74 | var saveAs = _global.saveAs || (
75 | // probably in some web worker
76 | (typeof window !== 'object' || window !== _global)
77 | ? function saveAs () { /* noop */ }
78 |
79 | // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
80 | : ('download' in HTMLAnchorElement.prototype && !isMacOSWebView)
81 | ? function saveAs (blob, name, opts) {
82 | var URL = _global.URL || _global.webkitURL
83 | // Namespace is used to prevent conflict w/ Chrome Poper Blocker extension (Issue #561)
84 | var a = document.createElementNS('http://www.w3.org/1999/xhtml', 'a')
85 | name = name || blob.name || 'download'
86 |
87 | a.download = name
88 | a.rel = 'noopener' // tabnabbing
89 |
90 | // TODO: detect chrome extensions & packaged apps
91 | // a.target = '_blank'
92 |
93 | if (typeof blob === 'string') {
94 | // Support regular links
95 | a.href = blob
96 | if (a.origin !== location.origin) {
97 | corsEnabled(a.href)
98 | ? download(blob, name, opts)
99 | : click(a, a.target = '_blank')
100 | } else {
101 | click(a)
102 | }
103 | } else {
104 | // Support blobs
105 | a.href = URL.createObjectURL(blob)
106 | setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s
107 | setTimeout(function () { click(a) }, 0)
108 | }
109 | }
110 |
111 | // Use msSaveOrOpenBlob as a second approach
112 | : 'msSaveOrOpenBlob' in navigator
113 | ? function saveAs (blob, name, opts) {
114 | name = name || blob.name || 'download'
115 |
116 | if (typeof blob === 'string') {
117 | if (corsEnabled(blob)) {
118 | download(blob, name, opts)
119 | } else {
120 | var a = document.createElement('a')
121 | a.href = blob
122 | a.target = '_blank'
123 | setTimeout(function () { click(a) })
124 | }
125 | } else {
126 | navigator.msSaveOrOpenBlob(bom(blob, opts), name)
127 | }
128 | }
129 |
130 | // Fallback to using FileReader and a popup
131 | : function saveAs (blob, name, opts, popup) {
132 | // Open a popup immediately do go around popup blocker
133 | // Mostly only available on user interaction and the fileReader is async so...
134 | popup = popup || open('', '_blank')
135 | if (popup) {
136 | popup.document.title =
137 | popup.document.body.innerText = 'downloading...'
138 | }
139 |
140 | if (typeof blob === 'string') return download(blob, name, opts)
141 |
142 | var force = blob.type === 'application/octet-stream'
143 | var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari
144 | var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
145 |
146 | if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') {
147 | // Safari doesn't allow downloading of blob URLs
148 | var reader = new FileReader()
149 | reader.onloadend = function () {
150 | var url = reader.result
151 | url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
152 | if (popup) popup.location.href = url
153 | else location = url
154 | popup = null // reverse-tabnabbing #460
155 | }
156 | reader.readAsDataURL(blob)
157 | } else {
158 | var URL = _global.URL || _global.webkitURL
159 | var url = URL.createObjectURL(blob)
160 | if (popup) popup.location = url
161 | else location.href = url
162 | popup = null // reverse-tabnabbing #460
163 | setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s
164 | }
165 | }
166 | )
167 |
168 | _global.saveAs = saveAs.saveAs = saveAs
169 |
170 | if (typeof module !== 'undefined') {
171 | module.exports = saveAs;
172 | }
173 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MSYS* | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/site/src/jsMain/kotlin/com/stevdza/san/components/ControlsView.kt:
--------------------------------------------------------------------------------
1 | package com.stevdza.san.components
2 |
3 | import androidx.compose.runtime.Composable
4 | import com.stevdza.san.model.EditorTheme
5 | import com.stevdza.san.util.Res
6 | import com.varabyte.kobweb.compose.css.Cursor
7 | import com.varabyte.kobweb.compose.ui.Modifier
8 | import com.varabyte.kobweb.compose.ui.modifiers.*
9 | import com.varabyte.kobweb.compose.ui.toAttrs
10 | import com.varabyte.kobweb.silk.components.layout.SimpleGrid
11 | import com.varabyte.kobweb.silk.components.layout.numColumns
12 | import com.varabyte.kobweb.silk.components.text.SpanText
13 | import org.jetbrains.compose.web.attributes.*
14 | import org.jetbrains.compose.web.css.AlignSelf
15 | import org.jetbrains.compose.web.css.px
16 | import org.jetbrains.compose.web.dom.*
17 |
18 | @Composable
19 | fun ControlsView(
20 | defaultPadding: Int,
21 | defaultFontSize: Int,
22 | defaultLineHeight: Int,
23 | defaultTheme: String,
24 | onPaddingChanged: (Int) -> Unit,
25 | onFontSizeChanged: (Int) -> Unit,
26 | onLineHeightChanged: (Int) -> Unit,
27 | onThemeChanged: (EditorTheme) -> Unit,
28 | ) {
29 | SimpleGrid(
30 | modifier = Modifier.margin(bottom = 20.px),
31 | numColumns = numColumns(base = 2, md = 3)
32 | ) {
33 | Div(
34 | attrs = Modifier
35 | .classNames("form-floating", "my-1", "mx-1")
36 | .toAttrs()
37 | ) {
38 | Input(
39 | attrs = Modifier
40 | .id(Res.Id.fontSize)
41 | .classNames("form-control")
42 | .width(150.px)
43 | .toAttrs {
44 | name("font-size")
45 | placeholder("Font-Size")
46 | min("14")
47 | max("30")
48 | value(defaultFontSize)
49 | onInput {
50 | val inputValue = it.value?.toInt() ?: 14
51 | onFontSizeChanged(inputValue)
52 | }
53 | },
54 | type = InputType.Number
55 | )
56 | Label(forId = Res.Id.fontSize) {
57 | Text("Font-Size")
58 | }
59 | }
60 | Div(
61 | attrs = Modifier
62 | .classNames("form-floating", "my-1", "mx-1")
63 | .toAttrs()
64 | ) {
65 | Input(
66 | attrs = Modifier
67 | .id(Res.Id.lineHeight)
68 | .classNames("form-control")
69 | .width(150.px)
70 | .toAttrs {
71 | name("line-height")
72 | placeholder("Line-Height")
73 | min("16")
74 | max("40")
75 | value(defaultLineHeight)
76 | onInput {
77 | val inputValue = it.value?.toInt() ?: 20
78 | onLineHeightChanged(inputValue)
79 | }
80 | },
81 | type = InputType.Number
82 | )
83 | Label(forId = Res.Id.lineHeight) {
84 | Text("Line-Height")
85 | }
86 | }
87 | Div(
88 | attrs = Modifier
89 | .classNames("form-floating", "my-1", "mx-1")
90 | .toAttrs()
91 | ) {
92 | Input(
93 | attrs = Modifier
94 | .id(Res.Id.padding)
95 | .classNames("form-control")
96 | .width(150.px)
97 | .toAttrs {
98 | name("padding")
99 | placeholder("Padding")
100 | min("10")
101 | max("100")
102 | value(defaultPadding)
103 | onInput {
104 | val inputValue = it.value?.toInt() ?: 10
105 | onPaddingChanged(inputValue)
106 | }
107 | },
108 | type = InputType.Number
109 | )
110 | Label(forId = Res.Id.padding) {
111 | Text("Padding")
112 | }
113 | }
114 | DropDown(
115 | selectedTheme = defaultTheme,
116 | onThemeChanged = onThemeChanged
117 | )
118 | Button(attrs = Modifier
119 | .classNames("btn", "btn-primary", "btn-md", "my-1", "mx-1")
120 | .onClick {
121 | js("hljs.highlightAll()") as Unit
122 | }
123 | .toAttrs()
124 | ) {
125 | Text("Apply Colors")
126 | }
127 | Button(attrs = Modifier
128 | .classNames("btn", "btn-primary", "btn-md", "my-1", "mx-1")
129 | .onClick { saveImage() }
130 | .toAttrs()
131 | ) {
132 | Text("Export")
133 | }
134 | }
135 | }
136 |
137 | @Composable
138 | private fun DropDown(
139 | selectedTheme: String,
140 | onThemeChanged: (EditorTheme) -> Unit
141 | ) {
142 | Div(
143 | attrs = Modifier
144 | .classNames("dropdown", "my-1", "mx-1")
145 | .fillMaxWidth()
146 | .alignSelf(AlignSelf.Center)
147 | .toAttrs()
148 | ) {
149 | Button(
150 | attrs = Modifier
151 | .classNames("btn", "btn-light", "dropdown-toggle", "btn-md")
152 | .toAttrs {
153 | attr("data-bs-toggle", "dropdown")
154 | }
155 | ) {
156 | Text(selectedTheme)
157 | }
158 | Ul(
159 | attrs = Modifier
160 | .classNames("dropdown-menu")
161 | .cursor(Cursor.Pointer)
162 | .toAttrs()
163 | ) {
164 | EditorTheme.values().forEach { theme ->
165 | Li(
166 | attrs = Modifier
167 | .classNames("dropdown-item")
168 | .onClick { onThemeChanged(theme) }
169 | .toAttrs()
170 | ) {
171 | SpanText(text = theme.name)
172 | }
173 | }
174 | }
175 | }
176 | }
177 |
178 | private fun saveImage() {
179 | js(
180 | "var node = document.getElementById('editor');\n" +
181 | "\n" +
182 | "var options = {\n" +
183 | " quality: 0.99,\n" +
184 | " width: node.clientWidth*4,\n" +
185 | " height: node.clientHeight*4,\n" +
186 | " style: {\n" +
187 | " 'transform': 'scale(4)',\n" +
188 | " 'transform-origin': 'top left',\n" +
189 | "}\n" +
190 | "};\n" +
191 | "\n" +
192 | "domtoimage.toBlob(node, options).then(function(blob) {\n" +
193 | " window.saveAs(blob, 'pretty-ko.png');\n" +
194 | "});"
195 | )
196 | }
--------------------------------------------------------------------------------
/site/.kobweb/site/logo.svg:
--------------------------------------------------------------------------------
1 |
51 |
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/logo.svg:
--------------------------------------------------------------------------------
1 |
51 |
--------------------------------------------------------------------------------
/site/.kobweb/site/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Pretty-KO
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |

28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
46 |
47 |
48 |
49 |
56 |
private val credits = "Kobweb Framework"
57 |
58 |
59 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/site/.kobweb/site/highlight.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Highlight.js v11.3.1 (git: 2a972d8658)
3 | (c) 2006-2021 Ivan Sagalaev and other contributors
4 | License: BSD-3-Clause
5 | */
6 | var hljs=function(){"use strict";var e={exports:{}};function t(e){
7 | return e instanceof Map?e.clear=e.delete=e.set=()=>{
8 | throw Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=()=>{
9 | throw Error("set is read-only")
10 | }),Object.freeze(e),Object.getOwnPropertyNames(e).forEach((n=>{var i=e[n]
11 | ;"object"!=typeof i||Object.isFrozen(i)||t(i)})),e}
12 | e.exports=t,e.exports.default=t;var n=e.exports;class i{constructor(e){
13 | void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
14 | ignoreMatch(){this.isMatchIgnored=!0}}function r(e){
15 | return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")
16 | }function s(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
17 | ;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const o=e=>!!e.kind
18 | ;class a{constructor(e,t){
19 | this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){
20 | this.buffer+=r(e)}openNode(e){if(!o(e))return;let t=e.kind
21 | ;t=e.sublanguage?"language-"+t:((e,{prefix:t})=>{if(e.includes(".")){
22 | const n=e.split(".")
23 | ;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ")
24 | }return`${t}${e}`})(t,{prefix:this.classPrefix}),this.span(t)}closeNode(e){
25 | o(e)&&(this.buffer+="")}value(){return this.buffer}span(e){
26 | this.buffer+=``}}class c{constructor(){this.rootNode={
27 | children:[]},this.stack=[this.rootNode]}get top(){
28 | return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
29 | this.top.children.push(e)}openNode(e){const t={kind:e,children:[]}
30 | ;this.add(t),this.stack.push(t)}closeNode(){
31 | if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
32 | for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
33 | walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){
34 | return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t),
35 | t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){
36 | "string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
37 | c._collapse(e)})))}}class l extends c{constructor(e){super(),this.options=e}
38 | addKeyword(e,t){""!==e&&(this.openNode(t),this.addText(e),this.closeNode())}
39 | addText(e){""!==e&&this.add(e)}addSublanguage(e,t){const n=e.root
40 | ;n.kind=t,n.sublanguage=!0,this.add(n)}toHTML(){
41 | return new a(this,this.options).value()}finalize(){return!0}}function g(e){
42 | return e?"string"==typeof e?e:e.source:null}function d(e){return f("(?=",e,")")}
43 | function u(e){return f("(?:",e,")*")}function h(e){return f("(?:",e,")?")}
44 | function f(...e){return e.map((e=>g(e))).join("")}function p(...e){const t=(e=>{
45 | const t=e[e.length-1]
46 | ;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{}
47 | })(e);return"("+(t.capture?"":"?:")+e.map((e=>g(e))).join("|")+")"}
48 | function b(e){return RegExp(e.toString()+"|").exec("").length-1}
49 | const m=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
50 | ;function E(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n
51 | ;let i=g(e),r="";for(;i.length>0;){const e=m.exec(i);if(!e){r+=i;break}
52 | r+=i.substring(0,e.index),
53 | i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?r+="\\"+(Number(e[1])+t):(r+=e[0],
54 | "("===e[0]&&n++)}return r})).map((e=>`(${e})`)).join(t)}
55 | const x="[a-zA-Z]\\w*",w="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",_="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",v="\\b(0b[01]+)",O={
56 | begin:"\\\\[\\s\\S]",relevance:0},k={scope:"string",begin:"'",end:"'",
57 | illegal:"\\n",contains:[O]},N={scope:"string",begin:'"',end:'"',illegal:"\\n",
58 | contains:[O]},M=(e,t,n={})=>{const i=s({scope:"comment",begin:e,end:t,
59 | contains:[]},n);i.contains.push({scope:"doctag",
60 | begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
61 | end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
62 | ;const r=p("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
63 | ;return i.contains.push({begin:f(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i
64 | },S=M("//","$"),R=M("/\\*","\\*/"),j=M("#","$");var A=Object.freeze({
65 | __proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:x,UNDERSCORE_IDENT_RE:w,
66 | NUMBER_RE:y,C_NUMBER_RE:_,BINARY_NUMBER_RE:v,
67 | RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
68 | SHEBANG:(e={})=>{const t=/^#![ ]*\//
69 | ;return e.binary&&(e.begin=f(t,/.*\b/,e.binary,/\b.*/)),s({scope:"meta",begin:t,
70 | end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)},
71 | BACKSLASH_ESCAPE:O,APOS_STRING_MODE:k,QUOTE_STRING_MODE:N,PHRASAL_WORDS_MODE:{
72 | begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
73 | },COMMENT:M,C_LINE_COMMENT_MODE:S,C_BLOCK_COMMENT_MODE:R,HASH_COMMENT_MODE:j,
74 | NUMBER_MODE:{scope:"number",begin:y,relevance:0},C_NUMBER_MODE:{scope:"number",
75 | begin:_,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:v,relevance:0},
76 | REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//,
77 | end:/\/[gimuy]*/,illegal:/\n/,contains:[O,{begin:/\[/,end:/\]/,relevance:0,
78 | contains:[O]}]}]},TITLE_MODE:{scope:"title",begin:x,relevance:0},
79 | UNDERSCORE_TITLE_MODE:{scope:"title",begin:w,relevance:0},METHOD_GUARD:{
80 | begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{
81 | "on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{
82 | t.data._beginMatch!==e[1]&&t.ignoreMatch()}})});function I(e,t){
83 | "."===e.input[e.index-1]&&t.ignoreMatch()}function T(e,t){
84 | void 0!==e.className&&(e.scope=e.className,delete e.className)}function L(e,t){
85 | t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
86 | e.__beforeBegin=I,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
87 | void 0===e.relevance&&(e.relevance=0))}function B(e,t){
88 | Array.isArray(e.illegal)&&(e.illegal=p(...e.illegal))}function D(e,t){
89 | if(e.match){
90 | if(e.begin||e.end)throw Error("begin & end are not supported with match")
91 | ;e.begin=e.match,delete e.match}}function P(e,t){
92 | void 0===e.relevance&&(e.relevance=1)}const H=(e,t)=>{if(!e.beforeMatch)return
93 | ;if(e.starts)throw Error("beforeMatch cannot be used with starts")
94 | ;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t]
95 | })),e.keywords=n.keywords,e.begin=f(n.beforeMatch,d(n.begin)),e.starts={
96 | relevance:0,contains:[Object.assign(n,{endsParent:!0})]
97 | },e.relevance=0,delete n.beforeMatch
98 | },C=["of","and","for","in","not","or","if","then","parent","list","value"]
99 | ;function $(e,t,n="keyword"){const i=Object.create(null)
100 | ;return"string"==typeof e?r(n,e.split(" ")):Array.isArray(e)?r(n,e):Object.keys(e).forEach((n=>{
101 | Object.assign(i,$(e[n],t,n))})),i;function r(e,n){
102 | t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|")
103 | ;i[n[0]]=[e,U(n[0],n[1])]}))}}function U(e,t){
104 | return t?Number(t):(e=>C.includes(e.toLowerCase()))(e)?0:1}const z={},K=e=>{
105 | console.error(e)},W=(e,...t)=>{console.log("WARN: "+e,...t)},X=(e,t)=>{
106 | z[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),z[`${e}/${t}`]=!0)
107 | },G=Error();function Z(e,t,{key:n}){let i=0;const r=e[n],s={},o={}
108 | ;for(let e=1;e<=t.length;e++)o[e+i]=r[e],s[e+i]=!0,i+=b(t[e-1])
109 | ;e[n]=o,e[n]._emit=s,e[n]._multi=!0}function F(e){(e=>{
110 | e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
111 | delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
112 | _wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
113 | }),(e=>{if(Array.isArray(e.begin)){
114 | if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
115 | G
116 | ;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"),
117 | G;Z(e,e.begin,{key:"beginScope"}),e.begin=E(e.begin,{joinWith:""})}})(e),(e=>{
118 | if(Array.isArray(e.end)){
119 | if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
120 | G
121 | ;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"),
122 | G;Z(e,e.end,{key:"endScope"}),e.end=E(e.end,{joinWith:""})}})(e)}function V(e){
123 | function t(t,n){
124 | return RegExp(g(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":""))
125 | }class n{constructor(){
126 | this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
127 | addRule(e,t){
128 | t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]),
129 | this.matchAt+=b(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
130 | ;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(E(e,{joinWith:"|"
131 | }),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
132 | ;const t=this.matcherRe.exec(e);if(!t)return null
133 | ;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n]
134 | ;return t.splice(0,n),Object.assign(t,i)}}class i{constructor(){
135 | this.rules=[],this.multiRegexes=[],
136 | this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
137 | if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n
138 | ;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))),
139 | t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){
140 | return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){
141 | this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){
142 | const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex
143 | ;let n=t.exec(e)
144 | ;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{
145 | const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)}
146 | return n&&(this.regexIndex+=n.position+1,
147 | this.regexIndex===this.count&&this.considerAll()),n}}
148 | if(e.compilerExtensions||(e.compilerExtensions=[]),
149 | e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
150 | ;return e.classNameAliases=s(e.classNameAliases||{}),function n(r,o){const a=r
151 | ;if(r.isCompiled)return a
152 | ;[T,D,F,H].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))),
153 | r.__beforeBegin=null,[L,B,P].forEach((e=>e(r,o))),r.isCompiled=!0;let c=null
154 | ;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords),
155 | c=r.keywords.$pattern,
156 | delete r.keywords.$pattern),c=c||/\w+/,r.keywords&&(r.keywords=$(r.keywords,e.case_insensitive)),
157 | a.keywordPatternRe=t(c,!0),
158 | o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(a.begin),r.end||r.endsWithParent||(r.end=/\B|\b/),
159 | r.end&&(a.endRe=t(a.end)),
160 | a.terminatorEnd=g(a.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)),
161 | r.illegal&&(a.illegalRe=t(r.illegal)),
162 | r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>s(e,{
163 | variants:null},t)))),e.cachedVariants?e.cachedVariants:q(e)?s(e,{
164 | starts:e.starts?s(e.starts):null
165 | }):Object.isFrozen(e)?s(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a)
166 | })),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new i
167 | ;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin"
168 | }))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end"
169 | }),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function q(e){
170 | return!!e&&(e.endsWithParent||q(e.starts))}class J extends Error{
171 | constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}}
172 | const Y=r,Q=s,ee=Symbol("nomatch");var te=(e=>{
173 | const t=Object.create(null),r=Object.create(null),s=[];let o=!0
174 | ;const a="Could not find the language '{}', did you forget to load/include a language module?",c={
175 | disableAutodetect:!0,name:"Plain text",contains:[]};let g={
176 | ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
177 | languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
178 | cssSelector:"pre code",languages:null,__emitter:l};function b(e){
179 | return g.noHighlightRe.test(e)}function m(e,t,n){let i="",r=""
180 | ;"object"==typeof t?(i=e,
181 | n=t.ignoreIllegals,r=t.language):(X("10.7.0","highlight(lang, code, ...args) has been deprecated."),
182 | X("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
183 | r=e,i=t),void 0===n&&(n=!0);const s={code:i,language:r};N("before:highlight",s)
184 | ;const o=s.result?s.result:E(s.language,s.code,n)
185 | ;return o.code=s.code,N("after:highlight",o),o}function E(e,n,r,s){
186 | const c=Object.create(null);function l(){if(!k.keywords)return void M.addText(S)
187 | ;let e=0;k.keywordPatternRe.lastIndex=0;let t=k.keywordPatternRe.exec(S),n=""
188 | ;for(;t;){n+=S.substring(e,t.index)
189 | ;const r=y.case_insensitive?t[0].toLowerCase():t[0],s=(i=r,k.keywords[i]);if(s){
190 | const[e,i]=s
191 | ;if(M.addText(n),n="",c[r]=(c[r]||0)+1,c[r]<=7&&(R+=i),e.startsWith("_"))n+=t[0];else{
192 | const n=y.classNameAliases[e]||e;M.addKeyword(t[0],n)}}else n+=t[0]
193 | ;e=k.keywordPatternRe.lastIndex,t=k.keywordPatternRe.exec(S)}var i
194 | ;n+=S.substr(e),M.addText(n)}function d(){null!=k.subLanguage?(()=>{
195 | if(""===S)return;let e=null;if("string"==typeof k.subLanguage){
196 | if(!t[k.subLanguage])return void M.addText(S)
197 | ;e=E(k.subLanguage,S,!0,N[k.subLanguage]),N[k.subLanguage]=e._top
198 | }else e=x(S,k.subLanguage.length?k.subLanguage:null)
199 | ;k.relevance>0&&(R+=e.relevance),M.addSublanguage(e._emitter,e.language)
200 | })():l(),S=""}function u(e,t){let n=1;for(;void 0!==t[n];){if(!e._emit[n]){n++
201 | ;continue}const i=y.classNameAliases[e[n]]||e[n],r=t[n]
202 | ;i?M.addKeyword(r,i):(S=r,l(),S=""),n++}}function h(e,t){
203 | return e.scope&&"string"==typeof e.scope&&M.openNode(y.classNameAliases[e.scope]||e.scope),
204 | e.beginScope&&(e.beginScope._wrap?(M.addKeyword(S,y.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
205 | S=""):e.beginScope._multi&&(u(e.beginScope,t),S="")),k=Object.create(e,{parent:{
206 | value:k}}),k}function f(e,t,n){let r=((e,t)=>{const n=e&&e.exec(t)
207 | ;return n&&0===n.index})(e.endRe,n);if(r){if(e["on:end"]){const n=new i(e)
208 | ;e["on:end"](t,n),n.isMatchIgnored&&(r=!1)}if(r){
209 | for(;e.endsParent&&e.parent;)e=e.parent;return e}}
210 | if(e.endsWithParent)return f(e.parent,t,n)}function p(e){
211 | return 0===k.matcher.regexIndex?(S+=e[0],1):(I=!0,0)}function b(e){
212 | const t=e[0],i=n.substr(e.index),r=f(k,e,i);if(!r)return ee;const s=k
213 | ;k.endScope&&k.endScope._wrap?(d(),
214 | M.addKeyword(t,k.endScope._wrap)):k.endScope&&k.endScope._multi?(d(),
215 | u(k.endScope,e)):s.skip?S+=t:(s.returnEnd||s.excludeEnd||(S+=t),
216 | d(),s.excludeEnd&&(S=t));do{
217 | k.scope&&M.closeNode(),k.skip||k.subLanguage||(R+=k.relevance),k=k.parent
218 | }while(k!==r.parent);return r.starts&&h(r.starts,e),s.returnEnd?0:t.length}
219 | let m={};function w(t,s){const a=s&&s[0];if(S+=t,null==a)return d(),0
220 | ;if("begin"===m.type&&"end"===s.type&&m.index===s.index&&""===a){
221 | if(S+=n.slice(s.index,s.index+1),!o){const t=Error(`0 width match regex (${e})`)
222 | ;throw t.languageName=e,t.badRule=m.rule,t}return 1}
223 | if(m=s,"begin"===s.type)return(e=>{
224 | const t=e[0],n=e.rule,r=new i(n),s=[n.__beforeBegin,n["on:begin"]]
225 | ;for(const n of s)if(n&&(n(e,r),r.isMatchIgnored))return p(t)
226 | ;return n.skip?S+=t:(n.excludeBegin&&(S+=t),
227 | d(),n.returnBegin||n.excludeBegin||(S=t)),h(n,e),n.returnBegin?0:t.length})(s)
228 | ;if("illegal"===s.type&&!r){
229 | const e=Error('Illegal lexeme "'+a+'" for mode "'+(k.scope||"")+'"')
230 | ;throw e.mode=k,e}if("end"===s.type){const e=b(s);if(e!==ee)return e}
231 | if("illegal"===s.type&&""===a)return 1
232 | ;if(A>1e5&&A>3*s.index)throw Error("potential infinite loop, way more iterations than matches")
233 | ;return S+=a,a.length}const y=v(e)
234 | ;if(!y)throw K(a.replace("{}",e)),Error('Unknown language: "'+e+'"')
235 | ;const _=V(y);let O="",k=s||_;const N={},M=new g.__emitter(g);(()=>{const e=[]
236 | ;for(let t=k;t!==y;t=t.parent)t.scope&&e.unshift(t.scope)
237 | ;e.forEach((e=>M.openNode(e)))})();let S="",R=0,j=0,A=0,I=!1;try{
238 | for(k.matcher.considerAll();;){
239 | A++,I?I=!1:k.matcher.considerAll(),k.matcher.lastIndex=j
240 | ;const e=k.matcher.exec(n);if(!e)break;const t=w(n.substring(j,e.index),e)
241 | ;j=e.index+t}return w(n.substr(j)),M.closeAllNodes(),M.finalize(),O=M.toHTML(),{
242 | language:e,value:O,relevance:R,illegal:!1,_emitter:M,_top:k}}catch(t){
243 | if(t.message&&t.message.includes("Illegal"))return{language:e,value:Y(n),
244 | illegal:!0,relevance:0,_illegalBy:{message:t.message,index:j,
245 | context:n.slice(j-100,j+100),mode:t.mode,resultSoFar:O},_emitter:M};if(o)return{
246 | language:e,value:Y(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:k}
247 | ;throw t}}function x(e,n){n=n||g.languages||Object.keys(t);const i=(e=>{
248 | const t={value:Y(e),illegal:!1,relevance:0,_top:c,_emitter:new g.__emitter(g)}
249 | ;return t._emitter.addText(e),t})(e),r=n.filter(v).filter(k).map((t=>E(t,e,!1)))
250 | ;r.unshift(i);const s=r.sort(((e,t)=>{
251 | if(e.relevance!==t.relevance)return t.relevance-e.relevance
252 | ;if(e.language&&t.language){if(v(e.language).supersetOf===t.language)return 1
253 | ;if(v(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=s,l=o
254 | ;return l.secondBest=a,l}function w(e){let t=null;const n=(e=>{
255 | let t=e.className+" ";t+=e.parentNode?e.parentNode.className:""
256 | ;const n=g.languageDetectRe.exec(t);if(n){const t=v(n[1])
257 | ;return t||(W(a.replace("{}",n[1])),
258 | W("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"}
259 | return t.split(/\s+/).find((e=>b(e)||v(e)))})(e);if(b(n))return
260 | ;if(N("before:highlightElement",{el:e,language:n
261 | }),e.children.length>0&&(g.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),
262 | console.warn("https://github.com/highlightjs/highlight.js/issues/2886"),
263 | console.warn(e)),
264 | g.throwUnescapedHTML))throw new J("One of your code blocks includes unescaped HTML.",e.innerHTML)
265 | ;t=e;const i=t.textContent,s=n?m(i,{language:n,ignoreIllegals:!0}):x(i)
266 | ;e.innerHTML=s.value,((e,t,n)=>{const i=t&&r[t]||n
267 | ;e.classList.add("hljs"),e.classList.add("language-"+i)
268 | })(e,n,s.language),e.result={language:s.language,re:s.relevance,
269 | relevance:s.relevance},s.secondBest&&(e.secondBest={
270 | language:s.secondBest.language,relevance:s.secondBest.relevance
271 | }),N("after:highlightElement",{el:e,result:s,text:i})}let y=!1;function _(){
272 | "loading"!==document.readyState?document.querySelectorAll(g.cssSelector).forEach(w):y=!0
273 | }function v(e){return e=(e||"").toLowerCase(),t[e]||t[r[e]]}
274 | function O(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
275 | r[e.toLowerCase()]=t}))}function k(e){const t=v(e)
276 | ;return t&&!t.disableAutodetect}function N(e,t){const n=e;s.forEach((e=>{
277 | e[n]&&e[n](t)}))}
278 | "undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{
279 | y&&_()}),!1),Object.assign(e,{highlight:m,highlightAuto:x,highlightAll:_,
280 | highlightElement:w,
281 | highlightBlock:e=>(X("10.7.0","highlightBlock will be removed entirely in v12.0"),
282 | X("10.7.0","Please use highlightElement now."),w(e)),configure:e=>{g=Q(g,e)},
283 | initHighlighting:()=>{
284 | _(),X("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},
285 | initHighlightingOnLoad:()=>{
286 | _(),X("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")
287 | },registerLanguage:(n,i)=>{let r=null;try{r=i(e)}catch(e){
288 | if(K("Language definition for '{}' could not be registered.".replace("{}",n)),
289 | !o)throw e;K(e),r=c}
290 | r.name||(r.name=n),t[n]=r,r.rawDefinition=i.bind(null,e),r.aliases&&O(r.aliases,{
291 | languageName:n})},unregisterLanguage:e=>{delete t[e]
292 | ;for(const t of Object.keys(r))r[t]===e&&delete r[t]},
293 | listLanguages:()=>Object.keys(t),getLanguage:v,registerAliases:O,
294 | autoDetection:k,inherit:Q,addPlugin:e=>{(e=>{
295 | e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{
296 | e["before:highlightBlock"](Object.assign({block:t.el},t))
297 | }),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{
298 | e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),s.push(e)}
299 | }),e.debugMode=()=>{o=!1},e.safeMode=()=>{o=!0
300 | },e.versionString="11.3.1",e.regex={concat:f,lookahead:d,either:p,optional:h,
301 | anyNumberOfTimes:u};for(const e in A)"object"==typeof A[e]&&n(A[e])
302 | ;return Object.assign(e,A),e})({});return te}()
303 | ;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);/*! `kotlin` grammar compiled for Highlight.js 11.3.1 */
304 | (()=>{var e=(()=>{"use strict"
305 | ;var e="\\.([0-9](_*[0-9])*)",n="[0-9a-fA-F](_*[0-9a-fA-F])*",a={
306 | className:"number",variants:[{
307 | begin:`(\\b([0-9](_*[0-9])*)((${e})|\\.)?|(${e}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`
308 | },{begin:`\\b([0-9](_*[0-9])*)((${e})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{
309 | begin:`(${e})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{
310 | begin:`\\b0[xX]((${n})\\.?|(${n})?\\.(${n}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`
311 | },{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${n})[lL]?\\b`},{
312 | begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],
313 | relevance:0};return e=>{const n={
314 | keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",
315 | built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",
316 | literal:"true false null"},i={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"
317 | },s={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},t={
318 | className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string",
319 | variants:[{begin:'"""',end:'"""(?=[^"])',contains:[t,s]},{begin:"'",end:"'",
320 | illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,
321 | contains:[e.BACKSLASH_ESCAPE,t,s]}]};s.contains.push(r);const l={
322 | className:"meta",
323 | begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"
324 | },c={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,
325 | end:/\)/,contains:[e.inherit(r,{className:"string"})]}]
326 | },o=a,b=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),E={
327 | variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,
328 | contains:[]}]},d=E;return d.variants[1].contains=[E],E.variants[1].contains=[d],
329 | {name:"Kotlin",aliases:["kt","kts"],keywords:n,
330 | contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",
331 | begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,b,{className:"keyword",
332 | begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",
333 | begin:/@\w+/}]}},i,l,c,{className:"function",beginKeywords:"fun",end:"[(]|$",
334 | returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{
335 | begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,
336 | contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin:/,end:/>/,
337 | keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,
338 | endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,
339 | endsWithParent:!0,contains:[E,e.C_LINE_COMMENT_MODE,b],relevance:0
340 | },e.C_LINE_COMMENT_MODE,b,l,c,r,e.C_NUMBER_MODE]},b]},{className:"class",
341 | beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,
342 | illegal:"extends implements",contains:[{
343 | beginKeywords:"public protected internal private constructor"
344 | },e.UNDERSCORE_TITLE_MODE,{className:"type",begin:/,end:/>/,excludeBegin:!0,
345 | excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,
346 | excludeBegin:!0,returnEnd:!0},l,c]},r,{className:"meta",begin:"^#!/usr/bin/env",
347 | end:"$",illegal:"\n"},o]}}})();hljs.registerLanguage("kotlin",e)})();
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/highlight.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Highlight.js v11.3.1 (git: 2a972d8658)
3 | (c) 2006-2021 Ivan Sagalaev and other contributors
4 | License: BSD-3-Clause
5 | */
6 | var hljs=function(){"use strict";var e={exports:{}};function t(e){
7 | return e instanceof Map?e.clear=e.delete=e.set=()=>{
8 | throw Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=()=>{
9 | throw Error("set is read-only")
10 | }),Object.freeze(e),Object.getOwnPropertyNames(e).forEach((n=>{var i=e[n]
11 | ;"object"!=typeof i||Object.isFrozen(i)||t(i)})),e}
12 | e.exports=t,e.exports.default=t;var n=e.exports;class i{constructor(e){
13 | void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
14 | ignoreMatch(){this.isMatchIgnored=!0}}function r(e){
15 | return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")
16 | }function s(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
17 | ;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const o=e=>!!e.kind
18 | ;class a{constructor(e,t){
19 | this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){
20 | this.buffer+=r(e)}openNode(e){if(!o(e))return;let t=e.kind
21 | ;t=e.sublanguage?"language-"+t:((e,{prefix:t})=>{if(e.includes(".")){
22 | const n=e.split(".")
23 | ;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ")
24 | }return`${t}${e}`})(t,{prefix:this.classPrefix}),this.span(t)}closeNode(e){
25 | o(e)&&(this.buffer+="")}value(){return this.buffer}span(e){
26 | this.buffer+=``}}class c{constructor(){this.rootNode={
27 | children:[]},this.stack=[this.rootNode]}get top(){
28 | return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
29 | this.top.children.push(e)}openNode(e){const t={kind:e,children:[]}
30 | ;this.add(t),this.stack.push(t)}closeNode(){
31 | if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
32 | for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
33 | walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){
34 | return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t),
35 | t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){
36 | "string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
37 | c._collapse(e)})))}}class l extends c{constructor(e){super(),this.options=e}
38 | addKeyword(e,t){""!==e&&(this.openNode(t),this.addText(e),this.closeNode())}
39 | addText(e){""!==e&&this.add(e)}addSublanguage(e,t){const n=e.root
40 | ;n.kind=t,n.sublanguage=!0,this.add(n)}toHTML(){
41 | return new a(this,this.options).value()}finalize(){return!0}}function g(e){
42 | return e?"string"==typeof e?e:e.source:null}function d(e){return f("(?=",e,")")}
43 | function u(e){return f("(?:",e,")*")}function h(e){return f("(?:",e,")?")}
44 | function f(...e){return e.map((e=>g(e))).join("")}function p(...e){const t=(e=>{
45 | const t=e[e.length-1]
46 | ;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{}
47 | })(e);return"("+(t.capture?"":"?:")+e.map((e=>g(e))).join("|")+")"}
48 | function b(e){return RegExp(e.toString()+"|").exec("").length-1}
49 | const m=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
50 | ;function E(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n
51 | ;let i=g(e),r="";for(;i.length>0;){const e=m.exec(i);if(!e){r+=i;break}
52 | r+=i.substring(0,e.index),
53 | i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?r+="\\"+(Number(e[1])+t):(r+=e[0],
54 | "("===e[0]&&n++)}return r})).map((e=>`(${e})`)).join(t)}
55 | const x="[a-zA-Z]\\w*",w="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",_="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",v="\\b(0b[01]+)",O={
56 | begin:"\\\\[\\s\\S]",relevance:0},k={scope:"string",begin:"'",end:"'",
57 | illegal:"\\n",contains:[O]},N={scope:"string",begin:'"',end:'"',illegal:"\\n",
58 | contains:[O]},M=(e,t,n={})=>{const i=s({scope:"comment",begin:e,end:t,
59 | contains:[]},n);i.contains.push({scope:"doctag",
60 | begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
61 | end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
62 | ;const r=p("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
63 | ;return i.contains.push({begin:f(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i
64 | },S=M("//","$"),R=M("/\\*","\\*/"),j=M("#","$");var A=Object.freeze({
65 | __proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:x,UNDERSCORE_IDENT_RE:w,
66 | NUMBER_RE:y,C_NUMBER_RE:_,BINARY_NUMBER_RE:v,
67 | RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
68 | SHEBANG:(e={})=>{const t=/^#![ ]*\//
69 | ;return e.binary&&(e.begin=f(t,/.*\b/,e.binary,/\b.*/)),s({scope:"meta",begin:t,
70 | end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)},
71 | BACKSLASH_ESCAPE:O,APOS_STRING_MODE:k,QUOTE_STRING_MODE:N,PHRASAL_WORDS_MODE:{
72 | begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
73 | },COMMENT:M,C_LINE_COMMENT_MODE:S,C_BLOCK_COMMENT_MODE:R,HASH_COMMENT_MODE:j,
74 | NUMBER_MODE:{scope:"number",begin:y,relevance:0},C_NUMBER_MODE:{scope:"number",
75 | begin:_,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:v,relevance:0},
76 | REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//,
77 | end:/\/[gimuy]*/,illegal:/\n/,contains:[O,{begin:/\[/,end:/\]/,relevance:0,
78 | contains:[O]}]}]},TITLE_MODE:{scope:"title",begin:x,relevance:0},
79 | UNDERSCORE_TITLE_MODE:{scope:"title",begin:w,relevance:0},METHOD_GUARD:{
80 | begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{
81 | "on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{
82 | t.data._beginMatch!==e[1]&&t.ignoreMatch()}})});function I(e,t){
83 | "."===e.input[e.index-1]&&t.ignoreMatch()}function T(e,t){
84 | void 0!==e.className&&(e.scope=e.className,delete e.className)}function L(e,t){
85 | t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
86 | e.__beforeBegin=I,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
87 | void 0===e.relevance&&(e.relevance=0))}function B(e,t){
88 | Array.isArray(e.illegal)&&(e.illegal=p(...e.illegal))}function D(e,t){
89 | if(e.match){
90 | if(e.begin||e.end)throw Error("begin & end are not supported with match")
91 | ;e.begin=e.match,delete e.match}}function P(e,t){
92 | void 0===e.relevance&&(e.relevance=1)}const H=(e,t)=>{if(!e.beforeMatch)return
93 | ;if(e.starts)throw Error("beforeMatch cannot be used with starts")
94 | ;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t]
95 | })),e.keywords=n.keywords,e.begin=f(n.beforeMatch,d(n.begin)),e.starts={
96 | relevance:0,contains:[Object.assign(n,{endsParent:!0})]
97 | },e.relevance=0,delete n.beforeMatch
98 | },C=["of","and","for","in","not","or","if","then","parent","list","value"]
99 | ;function $(e,t,n="keyword"){const i=Object.create(null)
100 | ;return"string"==typeof e?r(n,e.split(" ")):Array.isArray(e)?r(n,e):Object.keys(e).forEach((n=>{
101 | Object.assign(i,$(e[n],t,n))})),i;function r(e,n){
102 | t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|")
103 | ;i[n[0]]=[e,U(n[0],n[1])]}))}}function U(e,t){
104 | return t?Number(t):(e=>C.includes(e.toLowerCase()))(e)?0:1}const z={},K=e=>{
105 | console.error(e)},W=(e,...t)=>{console.log("WARN: "+e,...t)},X=(e,t)=>{
106 | z[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),z[`${e}/${t}`]=!0)
107 | },G=Error();function Z(e,t,{key:n}){let i=0;const r=e[n],s={},o={}
108 | ;for(let e=1;e<=t.length;e++)o[e+i]=r[e],s[e+i]=!0,i+=b(t[e-1])
109 | ;e[n]=o,e[n]._emit=s,e[n]._multi=!0}function F(e){(e=>{
110 | e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
111 | delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
112 | _wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
113 | }),(e=>{if(Array.isArray(e.begin)){
114 | if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
115 | G
116 | ;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"),
117 | G;Z(e,e.begin,{key:"beginScope"}),e.begin=E(e.begin,{joinWith:""})}})(e),(e=>{
118 | if(Array.isArray(e.end)){
119 | if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
120 | G
121 | ;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"),
122 | G;Z(e,e.end,{key:"endScope"}),e.end=E(e.end,{joinWith:""})}})(e)}function V(e){
123 | function t(t,n){
124 | return RegExp(g(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":""))
125 | }class n{constructor(){
126 | this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
127 | addRule(e,t){
128 | t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]),
129 | this.matchAt+=b(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
130 | ;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(E(e,{joinWith:"|"
131 | }),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
132 | ;const t=this.matcherRe.exec(e);if(!t)return null
133 | ;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n]
134 | ;return t.splice(0,n),Object.assign(t,i)}}class i{constructor(){
135 | this.rules=[],this.multiRegexes=[],
136 | this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
137 | if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n
138 | ;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))),
139 | t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){
140 | return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){
141 | this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){
142 | const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex
143 | ;let n=t.exec(e)
144 | ;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{
145 | const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)}
146 | return n&&(this.regexIndex+=n.position+1,
147 | this.regexIndex===this.count&&this.considerAll()),n}}
148 | if(e.compilerExtensions||(e.compilerExtensions=[]),
149 | e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
150 | ;return e.classNameAliases=s(e.classNameAliases||{}),function n(r,o){const a=r
151 | ;if(r.isCompiled)return a
152 | ;[T,D,F,H].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))),
153 | r.__beforeBegin=null,[L,B,P].forEach((e=>e(r,o))),r.isCompiled=!0;let c=null
154 | ;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords),
155 | c=r.keywords.$pattern,
156 | delete r.keywords.$pattern),c=c||/\w+/,r.keywords&&(r.keywords=$(r.keywords,e.case_insensitive)),
157 | a.keywordPatternRe=t(c,!0),
158 | o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(a.begin),r.end||r.endsWithParent||(r.end=/\B|\b/),
159 | r.end&&(a.endRe=t(a.end)),
160 | a.terminatorEnd=g(a.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)),
161 | r.illegal&&(a.illegalRe=t(r.illegal)),
162 | r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>s(e,{
163 | variants:null},t)))),e.cachedVariants?e.cachedVariants:q(e)?s(e,{
164 | starts:e.starts?s(e.starts):null
165 | }):Object.isFrozen(e)?s(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a)
166 | })),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new i
167 | ;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin"
168 | }))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end"
169 | }),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function q(e){
170 | return!!e&&(e.endsWithParent||q(e.starts))}class J extends Error{
171 | constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}}
172 | const Y=r,Q=s,ee=Symbol("nomatch");var te=(e=>{
173 | const t=Object.create(null),r=Object.create(null),s=[];let o=!0
174 | ;const a="Could not find the language '{}', did you forget to load/include a language module?",c={
175 | disableAutodetect:!0,name:"Plain text",contains:[]};let g={
176 | ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
177 | languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
178 | cssSelector:"pre code",languages:null,__emitter:l};function b(e){
179 | return g.noHighlightRe.test(e)}function m(e,t,n){let i="",r=""
180 | ;"object"==typeof t?(i=e,
181 | n=t.ignoreIllegals,r=t.language):(X("10.7.0","highlight(lang, code, ...args) has been deprecated."),
182 | X("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
183 | r=e,i=t),void 0===n&&(n=!0);const s={code:i,language:r};N("before:highlight",s)
184 | ;const o=s.result?s.result:E(s.language,s.code,n)
185 | ;return o.code=s.code,N("after:highlight",o),o}function E(e,n,r,s){
186 | const c=Object.create(null);function l(){if(!k.keywords)return void M.addText(S)
187 | ;let e=0;k.keywordPatternRe.lastIndex=0;let t=k.keywordPatternRe.exec(S),n=""
188 | ;for(;t;){n+=S.substring(e,t.index)
189 | ;const r=y.case_insensitive?t[0].toLowerCase():t[0],s=(i=r,k.keywords[i]);if(s){
190 | const[e,i]=s
191 | ;if(M.addText(n),n="",c[r]=(c[r]||0)+1,c[r]<=7&&(R+=i),e.startsWith("_"))n+=t[0];else{
192 | const n=y.classNameAliases[e]||e;M.addKeyword(t[0],n)}}else n+=t[0]
193 | ;e=k.keywordPatternRe.lastIndex,t=k.keywordPatternRe.exec(S)}var i
194 | ;n+=S.substr(e),M.addText(n)}function d(){null!=k.subLanguage?(()=>{
195 | if(""===S)return;let e=null;if("string"==typeof k.subLanguage){
196 | if(!t[k.subLanguage])return void M.addText(S)
197 | ;e=E(k.subLanguage,S,!0,N[k.subLanguage]),N[k.subLanguage]=e._top
198 | }else e=x(S,k.subLanguage.length?k.subLanguage:null)
199 | ;k.relevance>0&&(R+=e.relevance),M.addSublanguage(e._emitter,e.language)
200 | })():l(),S=""}function u(e,t){let n=1;for(;void 0!==t[n];){if(!e._emit[n]){n++
201 | ;continue}const i=y.classNameAliases[e[n]]||e[n],r=t[n]
202 | ;i?M.addKeyword(r,i):(S=r,l(),S=""),n++}}function h(e,t){
203 | return e.scope&&"string"==typeof e.scope&&M.openNode(y.classNameAliases[e.scope]||e.scope),
204 | e.beginScope&&(e.beginScope._wrap?(M.addKeyword(S,y.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
205 | S=""):e.beginScope._multi&&(u(e.beginScope,t),S="")),k=Object.create(e,{parent:{
206 | value:k}}),k}function f(e,t,n){let r=((e,t)=>{const n=e&&e.exec(t)
207 | ;return n&&0===n.index})(e.endRe,n);if(r){if(e["on:end"]){const n=new i(e)
208 | ;e["on:end"](t,n),n.isMatchIgnored&&(r=!1)}if(r){
209 | for(;e.endsParent&&e.parent;)e=e.parent;return e}}
210 | if(e.endsWithParent)return f(e.parent,t,n)}function p(e){
211 | return 0===k.matcher.regexIndex?(S+=e[0],1):(I=!0,0)}function b(e){
212 | const t=e[0],i=n.substr(e.index),r=f(k,e,i);if(!r)return ee;const s=k
213 | ;k.endScope&&k.endScope._wrap?(d(),
214 | M.addKeyword(t,k.endScope._wrap)):k.endScope&&k.endScope._multi?(d(),
215 | u(k.endScope,e)):s.skip?S+=t:(s.returnEnd||s.excludeEnd||(S+=t),
216 | d(),s.excludeEnd&&(S=t));do{
217 | k.scope&&M.closeNode(),k.skip||k.subLanguage||(R+=k.relevance),k=k.parent
218 | }while(k!==r.parent);return r.starts&&h(r.starts,e),s.returnEnd?0:t.length}
219 | let m={};function w(t,s){const a=s&&s[0];if(S+=t,null==a)return d(),0
220 | ;if("begin"===m.type&&"end"===s.type&&m.index===s.index&&""===a){
221 | if(S+=n.slice(s.index,s.index+1),!o){const t=Error(`0 width match regex (${e})`)
222 | ;throw t.languageName=e,t.badRule=m.rule,t}return 1}
223 | if(m=s,"begin"===s.type)return(e=>{
224 | const t=e[0],n=e.rule,r=new i(n),s=[n.__beforeBegin,n["on:begin"]]
225 | ;for(const n of s)if(n&&(n(e,r),r.isMatchIgnored))return p(t)
226 | ;return n.skip?S+=t:(n.excludeBegin&&(S+=t),
227 | d(),n.returnBegin||n.excludeBegin||(S=t)),h(n,e),n.returnBegin?0:t.length})(s)
228 | ;if("illegal"===s.type&&!r){
229 | const e=Error('Illegal lexeme "'+a+'" for mode "'+(k.scope||"")+'"')
230 | ;throw e.mode=k,e}if("end"===s.type){const e=b(s);if(e!==ee)return e}
231 | if("illegal"===s.type&&""===a)return 1
232 | ;if(A>1e5&&A>3*s.index)throw Error("potential infinite loop, way more iterations than matches")
233 | ;return S+=a,a.length}const y=v(e)
234 | ;if(!y)throw K(a.replace("{}",e)),Error('Unknown language: "'+e+'"')
235 | ;const _=V(y);let O="",k=s||_;const N={},M=new g.__emitter(g);(()=>{const e=[]
236 | ;for(let t=k;t!==y;t=t.parent)t.scope&&e.unshift(t.scope)
237 | ;e.forEach((e=>M.openNode(e)))})();let S="",R=0,j=0,A=0,I=!1;try{
238 | for(k.matcher.considerAll();;){
239 | A++,I?I=!1:k.matcher.considerAll(),k.matcher.lastIndex=j
240 | ;const e=k.matcher.exec(n);if(!e)break;const t=w(n.substring(j,e.index),e)
241 | ;j=e.index+t}return w(n.substr(j)),M.closeAllNodes(),M.finalize(),O=M.toHTML(),{
242 | language:e,value:O,relevance:R,illegal:!1,_emitter:M,_top:k}}catch(t){
243 | if(t.message&&t.message.includes("Illegal"))return{language:e,value:Y(n),
244 | illegal:!0,relevance:0,_illegalBy:{message:t.message,index:j,
245 | context:n.slice(j-100,j+100),mode:t.mode,resultSoFar:O},_emitter:M};if(o)return{
246 | language:e,value:Y(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:k}
247 | ;throw t}}function x(e,n){n=n||g.languages||Object.keys(t);const i=(e=>{
248 | const t={value:Y(e),illegal:!1,relevance:0,_top:c,_emitter:new g.__emitter(g)}
249 | ;return t._emitter.addText(e),t})(e),r=n.filter(v).filter(k).map((t=>E(t,e,!1)))
250 | ;r.unshift(i);const s=r.sort(((e,t)=>{
251 | if(e.relevance!==t.relevance)return t.relevance-e.relevance
252 | ;if(e.language&&t.language){if(v(e.language).supersetOf===t.language)return 1
253 | ;if(v(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=s,l=o
254 | ;return l.secondBest=a,l}function w(e){let t=null;const n=(e=>{
255 | let t=e.className+" ";t+=e.parentNode?e.parentNode.className:""
256 | ;const n=g.languageDetectRe.exec(t);if(n){const t=v(n[1])
257 | ;return t||(W(a.replace("{}",n[1])),
258 | W("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"}
259 | return t.split(/\s+/).find((e=>b(e)||v(e)))})(e);if(b(n))return
260 | ;if(N("before:highlightElement",{el:e,language:n
261 | }),e.children.length>0&&(g.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),
262 | console.warn("https://github.com/highlightjs/highlight.js/issues/2886"),
263 | console.warn(e)),
264 | g.throwUnescapedHTML))throw new J("One of your code blocks includes unescaped HTML.",e.innerHTML)
265 | ;t=e;const i=t.textContent,s=n?m(i,{language:n,ignoreIllegals:!0}):x(i)
266 | ;e.innerHTML=s.value,((e,t,n)=>{const i=t&&r[t]||n
267 | ;e.classList.add("hljs"),e.classList.add("language-"+i)
268 | })(e,n,s.language),e.result={language:s.language,re:s.relevance,
269 | relevance:s.relevance},s.secondBest&&(e.secondBest={
270 | language:s.secondBest.language,relevance:s.secondBest.relevance
271 | }),N("after:highlightElement",{el:e,result:s,text:i})}let y=!1;function _(){
272 | "loading"!==document.readyState?document.querySelectorAll(g.cssSelector).forEach(w):y=!0
273 | }function v(e){return e=(e||"").toLowerCase(),t[e]||t[r[e]]}
274 | function O(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
275 | r[e.toLowerCase()]=t}))}function k(e){const t=v(e)
276 | ;return t&&!t.disableAutodetect}function N(e,t){const n=e;s.forEach((e=>{
277 | e[n]&&e[n](t)}))}
278 | "undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{
279 | y&&_()}),!1),Object.assign(e,{highlight:m,highlightAuto:x,highlightAll:_,
280 | highlightElement:w,
281 | highlightBlock:e=>(X("10.7.0","highlightBlock will be removed entirely in v12.0"),
282 | X("10.7.0","Please use highlightElement now."),w(e)),configure:e=>{g=Q(g,e)},
283 | initHighlighting:()=>{
284 | _(),X("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},
285 | initHighlightingOnLoad:()=>{
286 | _(),X("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")
287 | },registerLanguage:(n,i)=>{let r=null;try{r=i(e)}catch(e){
288 | if(K("Language definition for '{}' could not be registered.".replace("{}",n)),
289 | !o)throw e;K(e),r=c}
290 | r.name||(r.name=n),t[n]=r,r.rawDefinition=i.bind(null,e),r.aliases&&O(r.aliases,{
291 | languageName:n})},unregisterLanguage:e=>{delete t[e]
292 | ;for(const t of Object.keys(r))r[t]===e&&delete r[t]},
293 | listLanguages:()=>Object.keys(t),getLanguage:v,registerAliases:O,
294 | autoDetection:k,inherit:Q,addPlugin:e=>{(e=>{
295 | e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{
296 | e["before:highlightBlock"](Object.assign({block:t.el},t))
297 | }),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{
298 | e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),s.push(e)}
299 | }),e.debugMode=()=>{o=!1},e.safeMode=()=>{o=!0
300 | },e.versionString="11.3.1",e.regex={concat:f,lookahead:d,either:p,optional:h,
301 | anyNumberOfTimes:u};for(const e in A)"object"==typeof A[e]&&n(A[e])
302 | ;return Object.assign(e,A),e})({});return te}()
303 | ;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);/*! `kotlin` grammar compiled for Highlight.js 11.3.1 */
304 | (()=>{var e=(()=>{"use strict"
305 | ;var e="\\.([0-9](_*[0-9])*)",n="[0-9a-fA-F](_*[0-9a-fA-F])*",a={
306 | className:"number",variants:[{
307 | begin:`(\\b([0-9](_*[0-9])*)((${e})|\\.)?|(${e}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`
308 | },{begin:`\\b([0-9](_*[0-9])*)((${e})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{
309 | begin:`(${e})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{
310 | begin:`\\b0[xX]((${n})\\.?|(${n})?\\.(${n}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`
311 | },{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${n})[lL]?\\b`},{
312 | begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],
313 | relevance:0};return e=>{const n={
314 | keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",
315 | built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",
316 | literal:"true false null"},i={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"
317 | },s={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},t={
318 | className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string",
319 | variants:[{begin:'"""',end:'"""(?=[^"])',contains:[t,s]},{begin:"'",end:"'",
320 | illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,
321 | contains:[e.BACKSLASH_ESCAPE,t,s]}]};s.contains.push(r);const l={
322 | className:"meta",
323 | begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"
324 | },c={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,
325 | end:/\)/,contains:[e.inherit(r,{className:"string"})]}]
326 | },o=a,b=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),E={
327 | variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,
328 | contains:[]}]},d=E;return d.variants[1].contains=[E],E.variants[1].contains=[d],
329 | {name:"Kotlin",aliases:["kt","kts"],keywords:n,
330 | contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",
331 | begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,b,{className:"keyword",
332 | begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",
333 | begin:/@\w+/}]}},i,l,c,{className:"function",beginKeywords:"fun",end:"[(]|$",
334 | returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{
335 | begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,
336 | contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin:/,end:/>/,
337 | keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,
338 | endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,
339 | endsWithParent:!0,contains:[E,e.C_LINE_COMMENT_MODE,b],relevance:0
340 | },e.C_LINE_COMMENT_MODE,b,l,c,r,e.C_NUMBER_MODE]},b]},{className:"class",
341 | beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,
342 | illegal:"extends implements",contains:[{
343 | beginKeywords:"public protected internal private constructor"
344 | },e.UNDERSCORE_TITLE_MODE,{className:"type",begin:/,end:/>/,excludeBegin:!0,
345 | excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,
346 | excludeBegin:!0,returnEnd:!0},l,c]},r,{className:"meta",begin:"^#!/usr/bin/env",
347 | end:"$",illegal:"\n"},o]}}})();hljs.registerLanguage("kotlin",e)})();
--------------------------------------------------------------------------------
/site/.kobweb/site/dom-to-image.js:
--------------------------------------------------------------------------------
1 | (function (global) {
2 | 'use strict';
3 |
4 | var util = newUtil();
5 | var inliner = newInliner();
6 | var fontFaces = newFontFaces();
7 | var images = newImages();
8 |
9 | // Default impl options
10 | var defaultOptions = {
11 | // Default is to fail on error, no placeholder
12 | imagePlaceholder: undefined,
13 | // Default cache bust is false, it will use the cache
14 | cacheBust: false
15 | };
16 |
17 | var domtoimage = {
18 | toSvg: toSvg,
19 | toPng: toPng,
20 | toJpeg: toJpeg,
21 | toBlob: toBlob,
22 | toPixelData: toPixelData,
23 | impl: {
24 | fontFaces: fontFaces,
25 | images: images,
26 | util: util,
27 | inliner: inliner,
28 | options: {}
29 | }
30 | };
31 |
32 | if (typeof module !== 'undefined')
33 | module.exports = domtoimage;
34 | else
35 | global.domtoimage = domtoimage;
36 |
37 |
38 | /**
39 | * @param {Node} node - The DOM Node object to render
40 | * @param {Object} options - Rendering options
41 | * @param {Function} options.filter - Should return true if passed node should be included in the output
42 | * (excluding node means excluding it's children as well). Not called on the root node.
43 | * @param {String} options.bgcolor - color for the background, any valid CSS color value.
44 | * @param {Number} options.width - width to be applied to node before rendering.
45 | * @param {Number} options.height - height to be applied to node before rendering.
46 | * @param {Object} options.style - an object whose properties to be copied to node's style before rendering.
47 | * @param {Number} options.quality - a Number between 0 and 1 indicating image quality (applicable to JPEG only),
48 | defaults to 1.0.
49 | * @param {String} options.imagePlaceholder - dataURL to use as a placeholder for failed images, default behaviour is to fail fast on images we can't fetch
50 | * @param {Boolean} options.cacheBust - set to true to cache bust by appending the time to the request url
51 | * @return {Promise} - A promise that is fulfilled with a SVG image data URL
52 | * */
53 | function toSvg(node, options) {
54 | options = options || {};
55 | copyOptions(options);
56 | return Promise.resolve(node)
57 | .then(function (node) {
58 | return cloneNode(node, options.filter, true);
59 | })
60 | .then(embedFonts)
61 | .then(inlineImages)
62 | .then(applyOptions)
63 | .then(function (clone) {
64 | return makeSvgDataUri(clone,
65 | options.width || util.width(node),
66 | options.height || util.height(node)
67 | );
68 | });
69 |
70 | function applyOptions(clone) {
71 | if (options.bgcolor) clone.style.backgroundColor = options.bgcolor;
72 |
73 | if (options.width) clone.style.width = options.width + 'px';
74 | if (options.height) clone.style.height = options.height + 'px';
75 |
76 | if (options.style)
77 | Object.keys(options.style).forEach(function (property) {
78 | clone.style[property] = options.style[property];
79 | });
80 |
81 | return clone;
82 | }
83 | }
84 |
85 | /**
86 | * @param {Node} node - The DOM Node object to render
87 | * @param {Object} options - Rendering options, @see {@link toSvg}
88 | * @return {Promise} - A promise that is fulfilled with a Uint8Array containing RGBA pixel data.
89 | * */
90 | function toPixelData(node, options) {
91 | return draw(node, options || {})
92 | .then(function (canvas) {
93 | return canvas.getContext('2d').getImageData(
94 | 0,
95 | 0,
96 | util.width(node),
97 | util.height(node)
98 | ).data;
99 | });
100 | }
101 |
102 | /**
103 | * @param {Node} node - The DOM Node object to render
104 | * @param {Object} options - Rendering options, @see {@link toSvg}
105 | * @return {Promise} - A promise that is fulfilled with a PNG image data URL
106 | * */
107 | function toPng(node, options) {
108 | return draw(node, options || {})
109 | .then(function (canvas) {
110 | return canvas.toDataURL();
111 | });
112 | }
113 |
114 | /**
115 | * @param {Node} node - The DOM Node object to render
116 | * @param {Object} options - Rendering options, @see {@link toSvg}
117 | * @return {Promise} - A promise that is fulfilled with a JPEG image data URL
118 | * */
119 | function toJpeg(node, options) {
120 | options = options || {};
121 | return draw(node, options)
122 | .then(function (canvas) {
123 | return canvas.toDataURL('image/jpeg', options.quality || 1.0);
124 | });
125 | }
126 |
127 | /**
128 | * @param {Node} node - The DOM Node object to render
129 | * @param {Object} options - Rendering options, @see {@link toSvg}
130 | * @return {Promise} - A promise that is fulfilled with a PNG image blob
131 | * */
132 | function toBlob(node, options) {
133 | return draw(node, options || {})
134 | .then(util.canvasToBlob);
135 | }
136 |
137 | function copyOptions(options) {
138 | // Copy options to impl options for use in impl
139 | if(typeof(options.imagePlaceholder) === 'undefined') {
140 | domtoimage.impl.options.imagePlaceholder = defaultOptions.imagePlaceholder;
141 | } else {
142 | domtoimage.impl.options.imagePlaceholder = options.imagePlaceholder;
143 | }
144 |
145 | if(typeof(options.cacheBust) === 'undefined') {
146 | domtoimage.impl.options.cacheBust = defaultOptions.cacheBust;
147 | } else {
148 | domtoimage.impl.options.cacheBust = options.cacheBust;
149 | }
150 | }
151 |
152 | function draw(domNode, options) {
153 | return toSvg(domNode, options)
154 | .then(util.makeImage)
155 | .then(util.delay(100))
156 | .then(function (image) {
157 | var canvas = newCanvas(domNode);
158 | canvas.getContext('2d').drawImage(image, 0, 0);
159 | return canvas;
160 | });
161 |
162 | function newCanvas(domNode) {
163 | var canvas = document.createElement('canvas');
164 | canvas.width = options.width || util.width(domNode);
165 | canvas.height = options.height || util.height(domNode);
166 |
167 | if (options.bgcolor) {
168 | var ctx = canvas.getContext('2d');
169 | ctx.fillStyle = options.bgcolor;
170 | ctx.fillRect(0, 0, canvas.width, canvas.height);
171 | }
172 |
173 | return canvas;
174 | }
175 | }
176 |
177 | function cloneNode(node, filter, root) {
178 | if (!root && filter && !filter(node)) return Promise.resolve();
179 |
180 | return Promise.resolve(node)
181 | .then(makeNodeCopy)
182 | .then(function (clone) {
183 | return cloneChildren(node, clone, filter);
184 | })
185 | .then(function (clone) {
186 | return processClone(node, clone);
187 | });
188 |
189 | function makeNodeCopy(node) {
190 | if (node instanceof HTMLCanvasElement) return util.makeImage(node.toDataURL());
191 | return node.cloneNode(false);
192 | }
193 |
194 | function cloneChildren(original, clone, filter) {
195 | var children = original.childNodes;
196 | if (children.length === 0) return Promise.resolve(clone);
197 |
198 | return cloneChildrenInOrder(clone, util.asArray(children), filter)
199 | .then(function () {
200 | return clone;
201 | });
202 |
203 | function cloneChildrenInOrder(parent, children, filter) {
204 | var done = Promise.resolve();
205 | children.forEach(function (child) {
206 | done = done
207 | .then(function () {
208 | return cloneNode(child, filter);
209 | })
210 | .then(function (childClone) {
211 | if (childClone) parent.appendChild(childClone);
212 | });
213 | });
214 | return done;
215 | }
216 | }
217 |
218 | function processClone(original, clone) {
219 | if (!(clone instanceof Element)) return clone;
220 |
221 | return Promise.resolve()
222 | .then(cloneStyle)
223 | .then(clonePseudoElements)
224 | .then(copyUserInput)
225 | .then(fixSvg)
226 | .then(function () {
227 | return clone;
228 | });
229 |
230 | function cloneStyle() {
231 | copyStyle(window.getComputedStyle(original), clone.style);
232 |
233 | function copyStyle(source, target) {
234 | if (source.cssText) target.cssText = source.cssText;
235 | else copyProperties(source, target);
236 |
237 | function copyProperties(source, target) {
238 | util.asArray(source).forEach(function (name) {
239 | target.setProperty(
240 | name,
241 | source.getPropertyValue(name),
242 | source.getPropertyPriority(name)
243 | );
244 | });
245 | }
246 | }
247 | }
248 |
249 | function clonePseudoElements() {
250 | [':before', ':after'].forEach(function (element) {
251 | clonePseudoElement(element);
252 | });
253 |
254 | function clonePseudoElement(element) {
255 | var style = window.getComputedStyle(original, element);
256 | var content = style.getPropertyValue('content');
257 |
258 | if (content === '' || content === 'none') return;
259 |
260 | var className = util.uid();
261 | clone.className = clone.className + ' ' + className;
262 | var styleElement = document.createElement('style');
263 | styleElement.appendChild(formatPseudoElementStyle(className, element, style));
264 | clone.appendChild(styleElement);
265 |
266 | function formatPseudoElementStyle(className, element, style) {
267 | var selector = '.' + className + ':' + element;
268 | var cssText = style.cssText ? formatCssText(style) : formatCssProperties(style);
269 | return document.createTextNode(selector + '{' + cssText + '}');
270 |
271 | function formatCssText(style) {
272 | var content = style.getPropertyValue('content');
273 | return style.cssText + ' content: ' + content + ';';
274 | }
275 |
276 | function formatCssProperties(style) {
277 |
278 | return util.asArray(style)
279 | .map(formatProperty)
280 | .join('; ') + ';';
281 |
282 | function formatProperty(name) {
283 | return name + ': ' +
284 | style.getPropertyValue(name) +
285 | (style.getPropertyPriority(name) ? ' !important' : '');
286 | }
287 | }
288 | }
289 | }
290 | }
291 |
292 | function copyUserInput() {
293 | if (original instanceof HTMLTextAreaElement) clone.innerHTML = original.value;
294 | if (original instanceof HTMLInputElement) clone.setAttribute("value", original.value);
295 | }
296 |
297 | function fixSvg() {
298 | if (!(clone instanceof SVGElement)) return;
299 | clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
300 |
301 | if (!(clone instanceof SVGRectElement)) return;
302 | ['width', 'height'].forEach(function (attribute) {
303 | var value = clone.getAttribute(attribute);
304 | if (!value) return;
305 |
306 | clone.style.setProperty(attribute, value);
307 | });
308 | }
309 | }
310 | }
311 |
312 | function embedFonts(node) {
313 | return fontFaces.resolveAll()
314 | .then(function (cssText) {
315 | var styleNode = document.createElement('style');
316 | node.appendChild(styleNode);
317 | styleNode.appendChild(document.createTextNode(cssText));
318 | return node;
319 | });
320 | }
321 |
322 | function inlineImages(node) {
323 | return images.inlineAll(node)
324 | .then(function () {
325 | return node;
326 | });
327 | }
328 |
329 | function makeSvgDataUri(node, width, height) {
330 | return Promise.resolve(node)
331 | .then(function (node) {
332 | node.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
333 | return new XMLSerializer().serializeToString(node);
334 | })
335 | .then(util.escapeXhtml)
336 | .then(function (xhtml) {
337 | return '' + xhtml + '';
338 | })
339 | .then(function (foreignObject) {
340 | return '';
342 | })
343 | .then(function (svg) {
344 | return 'data:image/svg+xml;charset=utf-8,' + svg;
345 | });
346 | }
347 |
348 | function newUtil() {
349 | return {
350 | escape: escape,
351 | parseExtension: parseExtension,
352 | mimeType: mimeType,
353 | dataAsUrl: dataAsUrl,
354 | isDataUrl: isDataUrl,
355 | canvasToBlob: canvasToBlob,
356 | resolveUrl: resolveUrl,
357 | getAndEncode: getAndEncode,
358 | uid: uid(),
359 | delay: delay,
360 | asArray: asArray,
361 | escapeXhtml: escapeXhtml,
362 | makeImage: makeImage,
363 | width: width,
364 | height: height
365 | };
366 |
367 | function mimes() {
368 | /*
369 | * Only WOFF and EOT mime types for fonts are 'real'
370 | * see http://www.iana.org/assignments/media-types/media-types.xhtml
371 | */
372 | var WOFF = 'application/font-woff';
373 | var JPEG = 'image/jpeg';
374 |
375 | return {
376 | 'woff': WOFF,
377 | 'woff2': WOFF,
378 | 'ttf': 'application/font-truetype',
379 | 'eot': 'application/vnd.ms-fontobject',
380 | 'png': 'image/png',
381 | 'jpg': JPEG,
382 | 'jpeg': JPEG,
383 | 'gif': 'image/gif',
384 | 'tiff': 'image/tiff',
385 | 'svg': 'image/svg+xml'
386 | };
387 | }
388 |
389 | function parseExtension(url) {
390 | var match = /\.([^\.\/]*?)$/g.exec(url);
391 | if (match) return match[1];
392 | else return '';
393 | }
394 |
395 | function mimeType(url) {
396 | var extension = parseExtension(url).toLowerCase();
397 | return mimes()[extension] || '';
398 | }
399 |
400 | function isDataUrl(url) {
401 | return url.search(/^(data:)/) !== -1;
402 | }
403 |
404 | function toBlob(canvas) {
405 | return new Promise(function (resolve) {
406 | var binaryString = window.atob(canvas.toDataURL().split(',')[1]);
407 | var length = binaryString.length;
408 | var binaryArray = new Uint8Array(length);
409 |
410 | for (var i = 0; i < length; i++)
411 | binaryArray[i] = binaryString.charCodeAt(i);
412 |
413 | resolve(new Blob([binaryArray], {
414 | type: 'image/png'
415 | }));
416 | });
417 | }
418 |
419 | function canvasToBlob(canvas) {
420 | if (canvas.toBlob)
421 | return new Promise(function (resolve) {
422 | canvas.toBlob(resolve);
423 | });
424 |
425 | return toBlob(canvas);
426 | }
427 |
428 | function resolveUrl(url, baseUrl) {
429 | var doc = document.implementation.createHTMLDocument();
430 | var base = doc.createElement('base');
431 | doc.head.appendChild(base);
432 | var a = doc.createElement('a');
433 | doc.body.appendChild(a);
434 | base.href = baseUrl;
435 | a.href = url;
436 | return a.href;
437 | }
438 |
439 | function uid() {
440 | var index = 0;
441 |
442 | return function () {
443 | return 'u' + fourRandomChars() + index++;
444 |
445 | function fourRandomChars() {
446 | /* see http://stackoverflow.com/a/6248722/2519373 */
447 | return ('0000' + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4);
448 | }
449 | };
450 | }
451 |
452 | function makeImage(uri) {
453 | return new Promise(function (resolve, reject) {
454 | var image = new Image();
455 | image.onload = function () {
456 | resolve(image);
457 | };
458 | image.onerror = reject;
459 | image.src = uri;
460 | });
461 | }
462 |
463 | function getAndEncode(url) {
464 | var TIMEOUT = 30000;
465 | if(domtoimage.impl.options.cacheBust) {
466 | // Cache bypass so we dont have CORS issues with cached images
467 | // Source: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache
468 | url += ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime();
469 | }
470 |
471 | return new Promise(function (resolve) {
472 | var request = new XMLHttpRequest();
473 |
474 | request.onreadystatechange = done;
475 | request.ontimeout = timeout;
476 | request.responseType = 'blob';
477 | request.timeout = TIMEOUT;
478 | request.open('GET', url, true);
479 | request.send();
480 |
481 | var placeholder;
482 | if(domtoimage.impl.options.imagePlaceholder) {
483 | var split = domtoimage.impl.options.imagePlaceholder.split(/,/);
484 | if(split && split[1]) {
485 | placeholder = split[1];
486 | }
487 | }
488 |
489 | function done() {
490 | if (request.readyState !== 4) return;
491 |
492 | if (request.status !== 200) {
493 | if(placeholder) {
494 | resolve(placeholder);
495 | } else {
496 | fail('cannot fetch resource: ' + url + ', status: ' + request.status);
497 | }
498 |
499 | return;
500 | }
501 |
502 | var encoder = new FileReader();
503 | encoder.onloadend = function () {
504 | var content = encoder.result.split(/,/)[1];
505 | resolve(content);
506 | };
507 | encoder.readAsDataURL(request.response);
508 | }
509 |
510 | function timeout() {
511 | if(placeholder) {
512 | resolve(placeholder);
513 | } else {
514 | fail('timeout of ' + TIMEOUT + 'ms occured while fetching resource: ' + url);
515 | }
516 | }
517 |
518 | function fail(message) {
519 | console.error(message);
520 | resolve('');
521 | }
522 | });
523 | }
524 |
525 | function dataAsUrl(content, type) {
526 | return 'data:' + type + ';base64,' + content;
527 | }
528 |
529 | function escape(string) {
530 | return string.replace(/([.*+?^${}()|\[\]\/\\])/g, '\\$1');
531 | }
532 |
533 | function delay(ms) {
534 | return function (arg) {
535 | return new Promise(function (resolve) {
536 | setTimeout(function () {
537 | resolve(arg);
538 | }, ms);
539 | });
540 | };
541 | }
542 |
543 | function asArray(arrayLike) {
544 | var array = [];
545 | var length = arrayLike.length;
546 | for (var i = 0; i < length; i++) array.push(arrayLike[i]);
547 | return array;
548 | }
549 |
550 | function escapeXhtml(string) {
551 | return string.replace(/#/g, '%23').replace(/\n/g, '%0A');
552 | }
553 |
554 | function width(node) {
555 | var leftBorder = px(node, 'border-left-width');
556 | var rightBorder = px(node, 'border-right-width');
557 | return node.scrollWidth + leftBorder + rightBorder;
558 | }
559 |
560 | function height(node) {
561 | var topBorder = px(node, 'border-top-width');
562 | var bottomBorder = px(node, 'border-bottom-width');
563 | return node.scrollHeight + topBorder + bottomBorder;
564 | }
565 |
566 | function px(node, styleProperty) {
567 | var value = window.getComputedStyle(node).getPropertyValue(styleProperty);
568 | return parseFloat(value.replace('px', ''));
569 | }
570 | }
571 |
572 | function newInliner() {
573 | var URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/g;
574 |
575 | return {
576 | inlineAll: inlineAll,
577 | shouldProcess: shouldProcess,
578 | impl: {
579 | readUrls: readUrls,
580 | inline: inline
581 | }
582 | };
583 |
584 | function shouldProcess(string) {
585 | return string.search(URL_REGEX) !== -1;
586 | }
587 |
588 | function readUrls(string) {
589 | var result = [];
590 | var match;
591 | while ((match = URL_REGEX.exec(string)) !== null) {
592 | result.push(match[1]);
593 | }
594 | return result.filter(function (url) {
595 | return !util.isDataUrl(url);
596 | });
597 | }
598 |
599 | function inline(string, url, baseUrl, get) {
600 | return Promise.resolve(url)
601 | .then(function (url) {
602 | return baseUrl ? util.resolveUrl(url, baseUrl) : url;
603 | })
604 | .then(get || util.getAndEncode)
605 | .then(function (data) {
606 | return util.dataAsUrl(data, util.mimeType(url));
607 | })
608 | .then(function (dataUrl) {
609 | return string.replace(urlAsRegex(url), '$1' + dataUrl + '$3');
610 | });
611 |
612 | function urlAsRegex(url) {
613 | return new RegExp('(url\\([\'"]?)(' + util.escape(url) + ')([\'"]?\\))', 'g');
614 | }
615 | }
616 |
617 | function inlineAll(string, baseUrl, get) {
618 | if (nothingToInline()) return Promise.resolve(string);
619 |
620 | return Promise.resolve(string)
621 | .then(readUrls)
622 | .then(function (urls) {
623 | var done = Promise.resolve(string);
624 | urls.forEach(function (url) {
625 | done = done.then(function (string) {
626 | return inline(string, url, baseUrl, get);
627 | });
628 | });
629 | return done;
630 | });
631 |
632 | function nothingToInline() {
633 | return !shouldProcess(string);
634 | }
635 | }
636 | }
637 |
638 | function newFontFaces() {
639 | return {
640 | resolveAll: resolveAll,
641 | impl: {
642 | readAll: readAll
643 | }
644 | };
645 |
646 | function resolveAll() {
647 | return readAll(document)
648 | .then(function (webFonts) {
649 | return Promise.all(
650 | webFonts.map(function (webFont) {
651 | return webFont.resolve();
652 | })
653 | );
654 | })
655 | .then(function (cssStrings) {
656 | return cssStrings.join('\n');
657 | });
658 | }
659 |
660 | function readAll() {
661 | return Promise.resolve(util.asArray(document.styleSheets))
662 | .then(getCssRules)
663 | .then(selectWebFontRules)
664 | .then(function (rules) {
665 | return rules.map(newWebFont);
666 | });
667 |
668 | function selectWebFontRules(cssRules) {
669 | return cssRules
670 | .filter(function (rule) {
671 | return rule.type === CSSRule.FONT_FACE_RULE;
672 | })
673 | .filter(function (rule) {
674 | return inliner.shouldProcess(rule.style.getPropertyValue('src'));
675 | });
676 | }
677 |
678 | function getCssRules(styleSheets) {
679 | var cssRules = [];
680 | styleSheets.forEach(function (sheet) {
681 | try {
682 | util.asArray(sheet.cssRules || []).forEach(cssRules.push.bind(cssRules));
683 | } catch (e) {
684 | console.log('Error while reading CSS rules from ' + sheet.href, e.toString());
685 | }
686 | });
687 | return cssRules;
688 | }
689 |
690 | function newWebFont(webFontRule) {
691 | return {
692 | resolve: function resolve() {
693 | var baseUrl = (webFontRule.parentStyleSheet || {}).href;
694 | return inliner.inlineAll(webFontRule.cssText, baseUrl);
695 | },
696 | src: function () {
697 | return webFontRule.style.getPropertyValue('src');
698 | }
699 | };
700 | }
701 | }
702 | }
703 |
704 | function newImages() {
705 | return {
706 | inlineAll: inlineAll,
707 | impl: {
708 | newImage: newImage
709 | }
710 | };
711 |
712 | function newImage(element) {
713 | return {
714 | inline: inline
715 | };
716 |
717 | function inline(get) {
718 | if (util.isDataUrl(element.src)) return Promise.resolve();
719 |
720 | return Promise.resolve(element.src)
721 | .then(get || util.getAndEncode)
722 | .then(function (data) {
723 | return util.dataAsUrl(data, util.mimeType(element.src));
724 | })
725 | .then(function (dataUrl) {
726 | return new Promise(function (resolve, reject) {
727 | element.onload = resolve;
728 | element.onerror = reject;
729 | element.src = dataUrl;
730 | });
731 | });
732 | }
733 | }
734 |
735 | function inlineAll(node) {
736 | if (!(node instanceof Element)) return Promise.resolve(node);
737 |
738 | return inlineBackground(node)
739 | .then(function () {
740 | if (node instanceof HTMLImageElement)
741 | return newImage(node).inline();
742 | else
743 | return Promise.all(
744 | util.asArray(node.childNodes).map(function (child) {
745 | return inlineAll(child);
746 | })
747 | );
748 | });
749 |
750 | function inlineBackground(node) {
751 | var background = node.style.getPropertyValue('background');
752 |
753 | if (!background) return Promise.resolve(node);
754 |
755 | return inliner.inlineAll(background)
756 | .then(function (inlined) {
757 | node.style.setProperty(
758 | 'background',
759 | inlined,
760 | node.style.getPropertyPriority('background')
761 | );
762 | })
763 | .then(function () {
764 | return node;
765 | });
766 | }
767 | }
768 | }
769 | })(this);
770 |
--------------------------------------------------------------------------------
/site/src/jsMain/resources/public/dom-to-image.js:
--------------------------------------------------------------------------------
1 | (function (global) {
2 | 'use strict';
3 |
4 | var util = newUtil();
5 | var inliner = newInliner();
6 | var fontFaces = newFontFaces();
7 | var images = newImages();
8 |
9 | // Default impl options
10 | var defaultOptions = {
11 | // Default is to fail on error, no placeholder
12 | imagePlaceholder: undefined,
13 | // Default cache bust is false, it will use the cache
14 | cacheBust: false
15 | };
16 |
17 | var domtoimage = {
18 | toSvg: toSvg,
19 | toPng: toPng,
20 | toJpeg: toJpeg,
21 | toBlob: toBlob,
22 | toPixelData: toPixelData,
23 | impl: {
24 | fontFaces: fontFaces,
25 | images: images,
26 | util: util,
27 | inliner: inliner,
28 | options: {}
29 | }
30 | };
31 |
32 | if (typeof module !== 'undefined')
33 | module.exports = domtoimage;
34 | else
35 | global.domtoimage = domtoimage;
36 |
37 |
38 | /**
39 | * @param {Node} node - The DOM Node object to render
40 | * @param {Object} options - Rendering options
41 | * @param {Function} options.filter - Should return true if passed node should be included in the output
42 | * (excluding node means excluding it's children as well). Not called on the root node.
43 | * @param {String} options.bgcolor - color for the background, any valid CSS color value.
44 | * @param {Number} options.width - width to be applied to node before rendering.
45 | * @param {Number} options.height - height to be applied to node before rendering.
46 | * @param {Object} options.style - an object whose properties to be copied to node's style before rendering.
47 | * @param {Number} options.quality - a Number between 0 and 1 indicating image quality (applicable to JPEG only),
48 | defaults to 1.0.
49 | * @param {String} options.imagePlaceholder - dataURL to use as a placeholder for failed images, default behaviour is to fail fast on images we can't fetch
50 | * @param {Boolean} options.cacheBust - set to true to cache bust by appending the time to the request url
51 | * @return {Promise} - A promise that is fulfilled with a SVG image data URL
52 | * */
53 | function toSvg(node, options) {
54 | options = options || {};
55 | copyOptions(options);
56 | return Promise.resolve(node)
57 | .then(function (node) {
58 | return cloneNode(node, options.filter, true);
59 | })
60 | .then(embedFonts)
61 | .then(inlineImages)
62 | .then(applyOptions)
63 | .then(function (clone) {
64 | return makeSvgDataUri(clone,
65 | options.width || util.width(node),
66 | options.height || util.height(node)
67 | );
68 | });
69 |
70 | function applyOptions(clone) {
71 | if (options.bgcolor) clone.style.backgroundColor = options.bgcolor;
72 |
73 | if (options.width) clone.style.width = options.width + 'px';
74 | if (options.height) clone.style.height = options.height + 'px';
75 |
76 | if (options.style)
77 | Object.keys(options.style).forEach(function (property) {
78 | clone.style[property] = options.style[property];
79 | });
80 |
81 | return clone;
82 | }
83 | }
84 |
85 | /**
86 | * @param {Node} node - The DOM Node object to render
87 | * @param {Object} options - Rendering options, @see {@link toSvg}
88 | * @return {Promise} - A promise that is fulfilled with a Uint8Array containing RGBA pixel data.
89 | * */
90 | function toPixelData(node, options) {
91 | return draw(node, options || {})
92 | .then(function (canvas) {
93 | return canvas.getContext('2d').getImageData(
94 | 0,
95 | 0,
96 | util.width(node),
97 | util.height(node)
98 | ).data;
99 | });
100 | }
101 |
102 | /**
103 | * @param {Node} node - The DOM Node object to render
104 | * @param {Object} options - Rendering options, @see {@link toSvg}
105 | * @return {Promise} - A promise that is fulfilled with a PNG image data URL
106 | * */
107 | function toPng(node, options) {
108 | return draw(node, options || {})
109 | .then(function (canvas) {
110 | return canvas.toDataURL();
111 | });
112 | }
113 |
114 | /**
115 | * @param {Node} node - The DOM Node object to render
116 | * @param {Object} options - Rendering options, @see {@link toSvg}
117 | * @return {Promise} - A promise that is fulfilled with a JPEG image data URL
118 | * */
119 | function toJpeg(node, options) {
120 | options = options || {};
121 | return draw(node, options)
122 | .then(function (canvas) {
123 | return canvas.toDataURL('image/jpeg', options.quality || 1.0);
124 | });
125 | }
126 |
127 | /**
128 | * @param {Node} node - The DOM Node object to render
129 | * @param {Object} options - Rendering options, @see {@link toSvg}
130 | * @return {Promise} - A promise that is fulfilled with a PNG image blob
131 | * */
132 | function toBlob(node, options) {
133 | return draw(node, options || {})
134 | .then(util.canvasToBlob);
135 | }
136 |
137 | function copyOptions(options) {
138 | // Copy options to impl options for use in impl
139 | if(typeof(options.imagePlaceholder) === 'undefined') {
140 | domtoimage.impl.options.imagePlaceholder = defaultOptions.imagePlaceholder;
141 | } else {
142 | domtoimage.impl.options.imagePlaceholder = options.imagePlaceholder;
143 | }
144 |
145 | if(typeof(options.cacheBust) === 'undefined') {
146 | domtoimage.impl.options.cacheBust = defaultOptions.cacheBust;
147 | } else {
148 | domtoimage.impl.options.cacheBust = options.cacheBust;
149 | }
150 | }
151 |
152 | function draw(domNode, options) {
153 | return toSvg(domNode, options)
154 | .then(util.makeImage)
155 | .then(util.delay(100))
156 | .then(function (image) {
157 | var canvas = newCanvas(domNode);
158 | canvas.getContext('2d').drawImage(image, 0, 0);
159 | return canvas;
160 | });
161 |
162 | function newCanvas(domNode) {
163 | var canvas = document.createElement('canvas');
164 | canvas.width = options.width || util.width(domNode);
165 | canvas.height = options.height || util.height(domNode);
166 |
167 | if (options.bgcolor) {
168 | var ctx = canvas.getContext('2d');
169 | ctx.fillStyle = options.bgcolor;
170 | ctx.fillRect(0, 0, canvas.width, canvas.height);
171 | }
172 |
173 | return canvas;
174 | }
175 | }
176 |
177 | function cloneNode(node, filter, root) {
178 | if (!root && filter && !filter(node)) return Promise.resolve();
179 |
180 | return Promise.resolve(node)
181 | .then(makeNodeCopy)
182 | .then(function (clone) {
183 | return cloneChildren(node, clone, filter);
184 | })
185 | .then(function (clone) {
186 | return processClone(node, clone);
187 | });
188 |
189 | function makeNodeCopy(node) {
190 | if (node instanceof HTMLCanvasElement) return util.makeImage(node.toDataURL());
191 | return node.cloneNode(false);
192 | }
193 |
194 | function cloneChildren(original, clone, filter) {
195 | var children = original.childNodes;
196 | if (children.length === 0) return Promise.resolve(clone);
197 |
198 | return cloneChildrenInOrder(clone, util.asArray(children), filter)
199 | .then(function () {
200 | return clone;
201 | });
202 |
203 | function cloneChildrenInOrder(parent, children, filter) {
204 | var done = Promise.resolve();
205 | children.forEach(function (child) {
206 | done = done
207 | .then(function () {
208 | return cloneNode(child, filter);
209 | })
210 | .then(function (childClone) {
211 | if (childClone) parent.appendChild(childClone);
212 | });
213 | });
214 | return done;
215 | }
216 | }
217 |
218 | function processClone(original, clone) {
219 | if (!(clone instanceof Element)) return clone;
220 |
221 | return Promise.resolve()
222 | .then(cloneStyle)
223 | .then(clonePseudoElements)
224 | .then(copyUserInput)
225 | .then(fixSvg)
226 | .then(function () {
227 | return clone;
228 | });
229 |
230 | function cloneStyle() {
231 | copyStyle(window.getComputedStyle(original), clone.style);
232 |
233 | function copyStyle(source, target) {
234 | if (source.cssText) target.cssText = source.cssText;
235 | else copyProperties(source, target);
236 |
237 | function copyProperties(source, target) {
238 | util.asArray(source).forEach(function (name) {
239 | target.setProperty(
240 | name,
241 | source.getPropertyValue(name),
242 | source.getPropertyPriority(name)
243 | );
244 | });
245 | }
246 | }
247 | }
248 |
249 | function clonePseudoElements() {
250 | [':before', ':after'].forEach(function (element) {
251 | clonePseudoElement(element);
252 | });
253 |
254 | function clonePseudoElement(element) {
255 | var style = window.getComputedStyle(original, element);
256 | var content = style.getPropertyValue('content');
257 |
258 | if (content === '' || content === 'none') return;
259 |
260 | var className = util.uid();
261 | clone.className = clone.className + ' ' + className;
262 | var styleElement = document.createElement('style');
263 | styleElement.appendChild(formatPseudoElementStyle(className, element, style));
264 | clone.appendChild(styleElement);
265 |
266 | function formatPseudoElementStyle(className, element, style) {
267 | var selector = '.' + className + ':' + element;
268 | var cssText = style.cssText ? formatCssText(style) : formatCssProperties(style);
269 | return document.createTextNode(selector + '{' + cssText + '}');
270 |
271 | function formatCssText(style) {
272 | var content = style.getPropertyValue('content');
273 | return style.cssText + ' content: ' + content + ';';
274 | }
275 |
276 | function formatCssProperties(style) {
277 |
278 | return util.asArray(style)
279 | .map(formatProperty)
280 | .join('; ') + ';';
281 |
282 | function formatProperty(name) {
283 | return name + ': ' +
284 | style.getPropertyValue(name) +
285 | (style.getPropertyPriority(name) ? ' !important' : '');
286 | }
287 | }
288 | }
289 | }
290 | }
291 |
292 | function copyUserInput() {
293 | if (original instanceof HTMLTextAreaElement) clone.innerHTML = original.value;
294 | if (original instanceof HTMLInputElement) clone.setAttribute("value", original.value);
295 | }
296 |
297 | function fixSvg() {
298 | if (!(clone instanceof SVGElement)) return;
299 | clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
300 |
301 | if (!(clone instanceof SVGRectElement)) return;
302 | ['width', 'height'].forEach(function (attribute) {
303 | var value = clone.getAttribute(attribute);
304 | if (!value) return;
305 |
306 | clone.style.setProperty(attribute, value);
307 | });
308 | }
309 | }
310 | }
311 |
312 | function embedFonts(node) {
313 | return fontFaces.resolveAll()
314 | .then(function (cssText) {
315 | var styleNode = document.createElement('style');
316 | node.appendChild(styleNode);
317 | styleNode.appendChild(document.createTextNode(cssText));
318 | return node;
319 | });
320 | }
321 |
322 | function inlineImages(node) {
323 | return images.inlineAll(node)
324 | .then(function () {
325 | return node;
326 | });
327 | }
328 |
329 | function makeSvgDataUri(node, width, height) {
330 | return Promise.resolve(node)
331 | .then(function (node) {
332 | node.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
333 | return new XMLSerializer().serializeToString(node);
334 | })
335 | .then(util.escapeXhtml)
336 | .then(function (xhtml) {
337 | return '' + xhtml + '';
338 | })
339 | .then(function (foreignObject) {
340 | return '';
342 | })
343 | .then(function (svg) {
344 | return 'data:image/svg+xml;charset=utf-8,' + svg;
345 | });
346 | }
347 |
348 | function newUtil() {
349 | return {
350 | escape: escape,
351 | parseExtension: parseExtension,
352 | mimeType: mimeType,
353 | dataAsUrl: dataAsUrl,
354 | isDataUrl: isDataUrl,
355 | canvasToBlob: canvasToBlob,
356 | resolveUrl: resolveUrl,
357 | getAndEncode: getAndEncode,
358 | uid: uid(),
359 | delay: delay,
360 | asArray: asArray,
361 | escapeXhtml: escapeXhtml,
362 | makeImage: makeImage,
363 | width: width,
364 | height: height
365 | };
366 |
367 | function mimes() {
368 | /*
369 | * Only WOFF and EOT mime types for fonts are 'real'
370 | * see http://www.iana.org/assignments/media-types/media-types.xhtml
371 | */
372 | var WOFF = 'application/font-woff';
373 | var JPEG = 'image/jpeg';
374 |
375 | return {
376 | 'woff': WOFF,
377 | 'woff2': WOFF,
378 | 'ttf': 'application/font-truetype',
379 | 'eot': 'application/vnd.ms-fontobject',
380 | 'png': 'image/png',
381 | 'jpg': JPEG,
382 | 'jpeg': JPEG,
383 | 'gif': 'image/gif',
384 | 'tiff': 'image/tiff',
385 | 'svg': 'image/svg+xml'
386 | };
387 | }
388 |
389 | function parseExtension(url) {
390 | var match = /\.([^\.\/]*?)$/g.exec(url);
391 | if (match) return match[1];
392 | else return '';
393 | }
394 |
395 | function mimeType(url) {
396 | var extension = parseExtension(url).toLowerCase();
397 | return mimes()[extension] || '';
398 | }
399 |
400 | function isDataUrl(url) {
401 | return url.search(/^(data:)/) !== -1;
402 | }
403 |
404 | function toBlob(canvas) {
405 | return new Promise(function (resolve) {
406 | var binaryString = window.atob(canvas.toDataURL().split(',')[1]);
407 | var length = binaryString.length;
408 | var binaryArray = new Uint8Array(length);
409 |
410 | for (var i = 0; i < length; i++)
411 | binaryArray[i] = binaryString.charCodeAt(i);
412 |
413 | resolve(new Blob([binaryArray], {
414 | type: 'image/png'
415 | }));
416 | });
417 | }
418 |
419 | function canvasToBlob(canvas) {
420 | if (canvas.toBlob)
421 | return new Promise(function (resolve) {
422 | canvas.toBlob(resolve);
423 | });
424 |
425 | return toBlob(canvas);
426 | }
427 |
428 | function resolveUrl(url, baseUrl) {
429 | var doc = document.implementation.createHTMLDocument();
430 | var base = doc.createElement('base');
431 | doc.head.appendChild(base);
432 | var a = doc.createElement('a');
433 | doc.body.appendChild(a);
434 | base.href = baseUrl;
435 | a.href = url;
436 | return a.href;
437 | }
438 |
439 | function uid() {
440 | var index = 0;
441 |
442 | return function () {
443 | return 'u' + fourRandomChars() + index++;
444 |
445 | function fourRandomChars() {
446 | /* see http://stackoverflow.com/a/6248722/2519373 */
447 | return ('0000' + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4);
448 | }
449 | };
450 | }
451 |
452 | function makeImage(uri) {
453 | return new Promise(function (resolve, reject) {
454 | var image = new Image();
455 | image.onload = function () {
456 | resolve(image);
457 | };
458 | image.onerror = reject;
459 | image.src = uri;
460 | });
461 | }
462 |
463 | function getAndEncode(url) {
464 | var TIMEOUT = 30000;
465 | if(domtoimage.impl.options.cacheBust) {
466 | // Cache bypass so we dont have CORS issues with cached images
467 | // Source: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache
468 | url += ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime();
469 | }
470 |
471 | return new Promise(function (resolve) {
472 | var request = new XMLHttpRequest();
473 |
474 | request.onreadystatechange = done;
475 | request.ontimeout = timeout;
476 | request.responseType = 'blob';
477 | request.timeout = TIMEOUT;
478 | request.open('GET', url, true);
479 | request.send();
480 |
481 | var placeholder;
482 | if(domtoimage.impl.options.imagePlaceholder) {
483 | var split = domtoimage.impl.options.imagePlaceholder.split(/,/);
484 | if(split && split[1]) {
485 | placeholder = split[1];
486 | }
487 | }
488 |
489 | function done() {
490 | if (request.readyState !== 4) return;
491 |
492 | if (request.status !== 200) {
493 | if(placeholder) {
494 | resolve(placeholder);
495 | } else {
496 | fail('cannot fetch resource: ' + url + ', status: ' + request.status);
497 | }
498 |
499 | return;
500 | }
501 |
502 | var encoder = new FileReader();
503 | encoder.onloadend = function () {
504 | var content = encoder.result.split(/,/)[1];
505 | resolve(content);
506 | };
507 | encoder.readAsDataURL(request.response);
508 | }
509 |
510 | function timeout() {
511 | if(placeholder) {
512 | resolve(placeholder);
513 | } else {
514 | fail('timeout of ' + TIMEOUT + 'ms occured while fetching resource: ' + url);
515 | }
516 | }
517 |
518 | function fail(message) {
519 | console.error(message);
520 | resolve('');
521 | }
522 | });
523 | }
524 |
525 | function dataAsUrl(content, type) {
526 | return 'data:' + type + ';base64,' + content;
527 | }
528 |
529 | function escape(string) {
530 | return string.replace(/([.*+?^${}()|\[\]\/\\])/g, '\\$1');
531 | }
532 |
533 | function delay(ms) {
534 | return function (arg) {
535 | return new Promise(function (resolve) {
536 | setTimeout(function () {
537 | resolve(arg);
538 | }, ms);
539 | });
540 | };
541 | }
542 |
543 | function asArray(arrayLike) {
544 | var array = [];
545 | var length = arrayLike.length;
546 | for (var i = 0; i < length; i++) array.push(arrayLike[i]);
547 | return array;
548 | }
549 |
550 | function escapeXhtml(string) {
551 | return string.replace(/#/g, '%23').replace(/\n/g, '%0A');
552 | }
553 |
554 | function width(node) {
555 | var leftBorder = px(node, 'border-left-width');
556 | var rightBorder = px(node, 'border-right-width');
557 | return node.scrollWidth + leftBorder + rightBorder;
558 | }
559 |
560 | function height(node) {
561 | var topBorder = px(node, 'border-top-width');
562 | var bottomBorder = px(node, 'border-bottom-width');
563 | return node.scrollHeight + topBorder + bottomBorder;
564 | }
565 |
566 | function px(node, styleProperty) {
567 | var value = window.getComputedStyle(node).getPropertyValue(styleProperty);
568 | return parseFloat(value.replace('px', ''));
569 | }
570 | }
571 |
572 | function newInliner() {
573 | var URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/g;
574 |
575 | return {
576 | inlineAll: inlineAll,
577 | shouldProcess: shouldProcess,
578 | impl: {
579 | readUrls: readUrls,
580 | inline: inline
581 | }
582 | };
583 |
584 | function shouldProcess(string) {
585 | return string.search(URL_REGEX) !== -1;
586 | }
587 |
588 | function readUrls(string) {
589 | var result = [];
590 | var match;
591 | while ((match = URL_REGEX.exec(string)) !== null) {
592 | result.push(match[1]);
593 | }
594 | return result.filter(function (url) {
595 | return !util.isDataUrl(url);
596 | });
597 | }
598 |
599 | function inline(string, url, baseUrl, get) {
600 | return Promise.resolve(url)
601 | .then(function (url) {
602 | return baseUrl ? util.resolveUrl(url, baseUrl) : url;
603 | })
604 | .then(get || util.getAndEncode)
605 | .then(function (data) {
606 | return util.dataAsUrl(data, util.mimeType(url));
607 | })
608 | .then(function (dataUrl) {
609 | return string.replace(urlAsRegex(url), '$1' + dataUrl + '$3');
610 | });
611 |
612 | function urlAsRegex(url) {
613 | return new RegExp('(url\\([\'"]?)(' + util.escape(url) + ')([\'"]?\\))', 'g');
614 | }
615 | }
616 |
617 | function inlineAll(string, baseUrl, get) {
618 | if (nothingToInline()) return Promise.resolve(string);
619 |
620 | return Promise.resolve(string)
621 | .then(readUrls)
622 | .then(function (urls) {
623 | var done = Promise.resolve(string);
624 | urls.forEach(function (url) {
625 | done = done.then(function (string) {
626 | return inline(string, url, baseUrl, get);
627 | });
628 | });
629 | return done;
630 | });
631 |
632 | function nothingToInline() {
633 | return !shouldProcess(string);
634 | }
635 | }
636 | }
637 |
638 | function newFontFaces() {
639 | return {
640 | resolveAll: resolveAll,
641 | impl: {
642 | readAll: readAll
643 | }
644 | };
645 |
646 | function resolveAll() {
647 | return readAll(document)
648 | .then(function (webFonts) {
649 | return Promise.all(
650 | webFonts.map(function (webFont) {
651 | return webFont.resolve();
652 | })
653 | );
654 | })
655 | .then(function (cssStrings) {
656 | return cssStrings.join('\n');
657 | });
658 | }
659 |
660 | function readAll() {
661 | return Promise.resolve(util.asArray(document.styleSheets))
662 | .then(getCssRules)
663 | .then(selectWebFontRules)
664 | .then(function (rules) {
665 | return rules.map(newWebFont);
666 | });
667 |
668 | function selectWebFontRules(cssRules) {
669 | return cssRules
670 | .filter(function (rule) {
671 | return rule.type === CSSRule.FONT_FACE_RULE;
672 | })
673 | .filter(function (rule) {
674 | return inliner.shouldProcess(rule.style.getPropertyValue('src'));
675 | });
676 | }
677 |
678 | function getCssRules(styleSheets) {
679 | var cssRules = [];
680 | styleSheets.forEach(function (sheet) {
681 | try {
682 | util.asArray(sheet.cssRules || []).forEach(cssRules.push.bind(cssRules));
683 | } catch (e) {
684 | console.log('Error while reading CSS rules from ' + sheet.href, e.toString());
685 | }
686 | });
687 | return cssRules;
688 | }
689 |
690 | function newWebFont(webFontRule) {
691 | return {
692 | resolve: function resolve() {
693 | var baseUrl = (webFontRule.parentStyleSheet || {}).href;
694 | return inliner.inlineAll(webFontRule.cssText, baseUrl);
695 | },
696 | src: function () {
697 | return webFontRule.style.getPropertyValue('src');
698 | }
699 | };
700 | }
701 | }
702 | }
703 |
704 | function newImages() {
705 | return {
706 | inlineAll: inlineAll,
707 | impl: {
708 | newImage: newImage
709 | }
710 | };
711 |
712 | function newImage(element) {
713 | return {
714 | inline: inline
715 | };
716 |
717 | function inline(get) {
718 | if (util.isDataUrl(element.src)) return Promise.resolve();
719 |
720 | return Promise.resolve(element.src)
721 | .then(get || util.getAndEncode)
722 | .then(function (data) {
723 | return util.dataAsUrl(data, util.mimeType(element.src));
724 | })
725 | .then(function (dataUrl) {
726 | return new Promise(function (resolve, reject) {
727 | element.onload = resolve;
728 | element.onerror = reject;
729 | element.src = dataUrl;
730 | });
731 | });
732 | }
733 | }
734 |
735 | function inlineAll(node) {
736 | if (!(node instanceof Element)) return Promise.resolve(node);
737 |
738 | return inlineBackground(node)
739 | .then(function () {
740 | if (node instanceof HTMLImageElement)
741 | return newImage(node).inline();
742 | else
743 | return Promise.all(
744 | util.asArray(node.childNodes).map(function (child) {
745 | return inlineAll(child);
746 | })
747 | );
748 | });
749 |
750 | function inlineBackground(node) {
751 | var background = node.style.getPropertyValue('background');
752 |
753 | if (!background) return Promise.resolve(node);
754 |
755 | return inliner.inlineAll(background)
756 | .then(function (inlined) {
757 | node.style.setProperty(
758 | 'background',
759 | inlined,
760 | node.style.getPropertyPriority('background')
761 | );
762 | })
763 | .then(function () {
764 | return node;
765 | });
766 | }
767 | }
768 | }
769 | })(this);
770 |
--------------------------------------------------------------------------------