├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ ├── mdbook-docs.yml │ ├── pages.yml │ └── publish-to-maven-central.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── DEVELOPER.md ├── LICENSE ├── README.md ├── api └── kweb-core.api ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts ├── repositories.settings.gradle.kts ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ └── buildsrc │ └── conventions │ ├── base.gradle.kts │ ├── kotlin-jvm.gradle.kts │ └── maven-publish.gradle.kts ├── docs ├── book.toml └── src │ ├── SUMMARY.md │ ├── components.md │ ├── dom.md │ ├── events.md │ ├── faq.md │ ├── gettingstarted.md │ ├── integrations.md │ ├── intro.md │ ├── js.md │ ├── routing.md │ ├── speed.md │ ├── state.md │ └── style.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme-video.gif ├── settings.gradle.kts └── src ├── main ├── kotlin │ ├── kweb │ │ ├── BootstrapJs.kt │ │ ├── CookieReceiver.kt │ │ ├── Element.kt │ │ ├── ElementCreator.kt │ │ ├── ElementCreatorExtns.kt │ │ ├── KtorFeature.kt │ │ ├── Kweb.kt │ │ ├── ValueElement.kt │ │ ├── WebBrowser.kt │ │ ├── attributes.kt │ │ ├── client │ │ │ ├── Client2ServerMessage.kt │ │ │ ├── ClientConnection.kt │ │ │ ├── HttpRequestInfo.kt │ │ │ ├── RemoteClientState.kt │ │ │ └── Server2ClientMessage.kt │ │ ├── components │ │ │ └── Component.kt │ │ ├── config │ │ │ ├── KwebConfiguration.kt │ │ │ └── KwebDefaultConfiguration.kt │ │ ├── html │ │ │ ├── BodyElement.kt │ │ │ ├── Document.kt │ │ │ ├── HeadElement.kt │ │ │ ├── HtmlDocumentSupplier.kt │ │ │ ├── StorageReceiver.kt │ │ │ ├── Window.kt │ │ │ ├── events │ │ │ │ ├── EventGenerator.kt │ │ │ │ ├── OnImmediateReceiver.kt │ │ │ │ ├── OnReceiver.kt │ │ │ │ └── events.kt │ │ │ ├── fileUpload │ │ │ │ ├── FileFormInput.kt │ │ │ │ └── FileUpload.kt │ │ │ └── style │ │ │ │ └── style.kt │ │ ├── https │ │ │ └── SSLConfig.kt │ │ ├── plugins │ │ │ ├── FaviconPlugin.kt │ │ │ ├── KwebPlugin.kt │ │ │ ├── css │ │ │ │ └── CSSPlugin.kt │ │ │ ├── fomanticUI │ │ │ │ ├── FomanticUIClasses.kt │ │ │ │ ├── FomanticUIPlugin.kt │ │ │ │ └── jquery.kt │ │ │ ├── image │ │ │ │ └── DynamicImagePlugin.kt │ │ │ ├── javascript │ │ │ │ └── JavascriptPlugin.kt │ │ │ ├── jqueryCore │ │ │ │ ├── JQueryCorePlugin.kt │ │ │ │ ├── jqueryExtensions.kt │ │ │ │ └── jqueryevents.kt │ │ │ ├── specificKeyUp │ │ │ │ └── SpecificKeyUp.kt │ │ │ ├── staticFiles │ │ │ │ └── StaticFilesPlugin.kt │ │ │ └── viewport │ │ │ │ └── ViewportPlugin.kt │ │ ├── prelude.kt │ │ ├── routing │ │ │ ├── RouteReceiver.kt │ │ │ ├── UrlToPathSegmentsRF.kt │ │ │ └── routing.kt │ │ ├── state │ │ │ ├── KVal.kt │ │ │ ├── KVar.kt │ │ │ ├── ObservableList.kt │ │ │ ├── ReversibleFunction.kt │ │ │ ├── render.kt │ │ │ └── renderEach.kt │ │ ├── table.kt │ │ └── util │ │ │ ├── Template.kt │ │ │ ├── json.kt │ │ │ └── misc.kt │ └── packages.md └── resources │ ├── hotswap-agent.properties │ └── kweb │ ├── kweb_bootstrap.js │ └── static │ ├── plugins │ ├── fomantic │ │ ├── components │ │ │ ├── accordion.css │ │ │ ├── accordion.js │ │ │ ├── accordion.min.css │ │ │ ├── accordion.min.js │ │ │ ├── ad.css │ │ │ ├── ad.min.css │ │ │ ├── api.js │ │ │ ├── api.min.js │ │ │ ├── breadcrumb.css │ │ │ ├── breadcrumb.min.css │ │ │ ├── button.css │ │ │ ├── button.min.css │ │ │ ├── calendar.css │ │ │ ├── calendar.js │ │ │ ├── calendar.min.css │ │ │ ├── calendar.min.js │ │ │ ├── card.css │ │ │ ├── card.min.css │ │ │ ├── checkbox.css │ │ │ ├── checkbox.js │ │ │ ├── checkbox.min.css │ │ │ ├── checkbox.min.js │ │ │ ├── comment.css │ │ │ ├── comment.min.css │ │ │ ├── container.css │ │ │ ├── container.min.css │ │ │ ├── dimmer.css │ │ │ ├── dimmer.js │ │ │ ├── dimmer.min.css │ │ │ ├── dimmer.min.js │ │ │ ├── divider.css │ │ │ ├── divider.min.css │ │ │ ├── dropdown.css │ │ │ ├── dropdown.js │ │ │ ├── dropdown.min.css │ │ │ ├── dropdown.min.js │ │ │ ├── embed.css │ │ │ ├── embed.js │ │ │ ├── embed.min.css │ │ │ ├── embed.min.js │ │ │ ├── emoji.css │ │ │ ├── emoji.min.css │ │ │ ├── feed.css │ │ │ ├── feed.min.css │ │ │ ├── flag.css │ │ │ ├── flag.min.css │ │ │ ├── flyout.css │ │ │ ├── flyout.js │ │ │ ├── flyout.min.css │ │ │ ├── flyout.min.js │ │ │ ├── form.css │ │ │ ├── form.js │ │ │ ├── form.min.css │ │ │ ├── form.min.js │ │ │ ├── grid.css │ │ │ ├── grid.min.css │ │ │ ├── header.css │ │ │ ├── header.min.css │ │ │ ├── icon.css │ │ │ ├── icon.min.css │ │ │ ├── image.css │ │ │ ├── image.min.css │ │ │ ├── input.css │ │ │ ├── input.min.css │ │ │ ├── item.css │ │ │ ├── item.min.css │ │ │ ├── label.css │ │ │ ├── label.min.css │ │ │ ├── list.css │ │ │ ├── list.min.css │ │ │ ├── loader.css │ │ │ ├── loader.min.css │ │ │ ├── menu.css │ │ │ ├── menu.min.css │ │ │ ├── message.css │ │ │ ├── message.min.css │ │ │ ├── modal.css │ │ │ ├── modal.js │ │ │ ├── modal.min.css │ │ │ ├── modal.min.js │ │ │ ├── nag.css │ │ │ ├── nag.js │ │ │ ├── nag.min.css │ │ │ ├── nag.min.js │ │ │ ├── placeholder.css │ │ │ ├── placeholder.min.css │ │ │ ├── popup.css │ │ │ ├── popup.js │ │ │ ├── popup.min.css │ │ │ ├── popup.min.js │ │ │ ├── progress.css │ │ │ ├── progress.js │ │ │ ├── progress.min.css │ │ │ ├── progress.min.js │ │ │ ├── rail.css │ │ │ ├── rail.min.css │ │ │ ├── rating.css │ │ │ ├── rating.js │ │ │ ├── rating.min.css │ │ │ ├── rating.min.js │ │ │ ├── reset.css │ │ │ ├── reset.min.css │ │ │ ├── reveal.css │ │ │ ├── reveal.min.css │ │ │ ├── search.css │ │ │ ├── search.js │ │ │ ├── search.min.css │ │ │ ├── search.min.js │ │ │ ├── segment.css │ │ │ ├── segment.min.css │ │ │ ├── shape.css │ │ │ ├── shape.js │ │ │ ├── shape.min.css │ │ │ ├── shape.min.js │ │ │ ├── sidebar.css │ │ │ ├── sidebar.js │ │ │ ├── sidebar.min.css │ │ │ ├── sidebar.min.js │ │ │ ├── site.css │ │ │ ├── site.js │ │ │ ├── site.min.css │ │ │ ├── site.min.js │ │ │ ├── slider.css │ │ │ ├── slider.js │ │ │ ├── slider.min.css │ │ │ ├── slider.min.js │ │ │ ├── state.js │ │ │ ├── state.min.js │ │ │ ├── statistic.css │ │ │ ├── statistic.min.css │ │ │ ├── step.css │ │ │ ├── step.min.css │ │ │ ├── sticky.css │ │ │ ├── sticky.js │ │ │ ├── sticky.min.css │ │ │ ├── sticky.min.js │ │ │ ├── tab.css │ │ │ ├── tab.js │ │ │ ├── tab.min.css │ │ │ ├── tab.min.js │ │ │ ├── table.css │ │ │ ├── table.min.css │ │ │ ├── text.css │ │ │ ├── text.min.css │ │ │ ├── toast.css │ │ │ ├── toast.js │ │ │ ├── toast.min.css │ │ │ ├── toast.min.js │ │ │ ├── transition.css │ │ │ ├── transition.js │ │ │ ├── transition.min.css │ │ │ ├── transition.min.js │ │ │ ├── visibility.js │ │ │ └── visibility.min.js │ │ ├── semantic.css │ │ ├── semantic.js │ │ ├── semantic.min.css │ │ ├── semantic.min.js │ │ └── themes │ │ │ ├── basic │ │ │ └── assets │ │ │ │ └── fonts │ │ │ │ ├── icons.woff │ │ │ │ └── icons.woff2 │ │ │ ├── default │ │ │ └── assets │ │ │ │ └── fonts │ │ │ │ ├── Lato-Bold.woff │ │ │ │ ├── Lato-Bold.woff2 │ │ │ │ ├── Lato-BoldItalic.woff │ │ │ │ ├── Lato-BoldItalic.woff2 │ │ │ │ ├── Lato-Italic.woff │ │ │ │ ├── Lato-Italic.woff2 │ │ │ │ ├── Lato-Regular.woff │ │ │ │ ├── Lato-Regular.woff2 │ │ │ │ ├── LatoLatin-Bold.woff │ │ │ │ ├── LatoLatin-Bold.woff2 │ │ │ │ ├── LatoLatin-BoldItalic.woff │ │ │ │ ├── LatoLatin-BoldItalic.woff2 │ │ │ │ ├── LatoLatin-Italic.woff │ │ │ │ ├── LatoLatin-Italic.woff2 │ │ │ │ ├── LatoLatin-Regular.woff │ │ │ │ ├── LatoLatin-Regular.woff2 │ │ │ │ ├── brand-icons.woff │ │ │ │ ├── brand-icons.woff2 │ │ │ │ ├── icons.woff │ │ │ │ ├── icons.woff2 │ │ │ │ ├── outline-icons.woff │ │ │ │ └── outline-icons.woff2 │ │ │ ├── famfamfam │ │ │ └── assets │ │ │ │ └── images │ │ │ │ └── flags.png │ │ │ ├── github │ │ │ └── assets │ │ │ │ └── fonts │ │ │ │ ├── octicons.woff │ │ │ │ └── octicons.woff2 │ │ │ └── material │ │ │ └── assets │ │ │ └── fonts │ │ │ ├── icons.woff │ │ │ └── icons.woff2 │ └── jquery │ │ └── jquery-3.6.1.min.js │ └── toastify │ ├── toastify.js │ └── toastify.min.css └── test ├── kotlin └── kweb │ ├── HistoryTest.kt │ ├── HrefTest.kt │ ├── ImmediateEventTest.kt │ ├── InputCheckedTest.kt │ ├── SelectInitialValueTest.kt │ ├── SelectValueTest.kt │ ├── StringDiffTest.kt │ ├── TextAreaInitialValueTest.kt │ ├── client │ └── ClientConnectionTest.kt │ ├── demos │ └── todo │ │ ├── TodoApp.kt │ │ └── TodoDemoTest.kt │ ├── docs │ ├── components.kt │ ├── dom.kt │ ├── events.kt │ ├── gettingstarted.kt │ ├── js.kt │ ├── readme.kt │ ├── state.kt │ └── style.kt │ ├── routing │ ├── RoutingSpec.kt │ └── UrlToPathSegmentsRFTest.kt │ └── state │ ├── KVarSpec.kt │ ├── ObservableListSpec.kt │ ├── StateSpec.kt │ ├── persistent │ └── PersistentSpec.kt │ └── render │ ├── RenderEachTest.kt │ └── RenderTest.kt └── resources ├── kweb └── phantomInit.js └── logback-test.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-vendored 2 | *.kt linguist-vendored=false 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gradle" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | day: "saturday" 8 | time: "09:00" 9 | timezone: "America/Chicago" 10 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build, test, and deploy API docs 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | paths-ignore: [ 'docs/**', 'README.md' ] 7 | pull_request: 8 | branches: [ master ] 9 | release: 10 | types: [published] 11 | workflow_dispatch: 12 | 13 | concurrency: 14 | group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v3 22 | with: 23 | fetch-depth: 0 24 | - name: Set up JDK 17 25 | uses: actions/setup-java@v3 26 | with: 27 | distribution: temurin 28 | java-version: 17 29 | 30 | - name: Setup Gradle 31 | uses: gradle/gradle-build-action@v2 32 | 33 | - name: Build and run tests 34 | id: build 35 | run: | 36 | if ! ./gradlew build; then 37 | # Address a rare unit test failure very likely to be a test-harness-related 38 | # race condition. 39 | echo "Build failed, retrying once" 40 | if ! ./gradlew build; then 41 | exit 1 42 | fi 43 | fi 44 | - name: Generate API documentation 45 | if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' }} 46 | run: | 47 | VERSION=$(git tag --sort=committerdate | tail -1) 48 | echo Generating API documentation for version $VERSION 49 | ./gradlew -Pversion=$VERSION dokkaHtml 50 | 51 | - name: Deploy API documentation to Github Pages 52 | if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' }} 53 | uses: JamesIves/github-pages-deploy-action@v4 54 | with: 55 | branch: gh-pages 56 | folder: build/dokka/html 57 | target-folder: api 58 | -------------------------------------------------------------------------------- /.github/workflows/mdbook-docs.yml: -------------------------------------------------------------------------------- 1 | name: Generate User Manual 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | push: 7 | branches: [master] 8 | paths-ignore: [ 'README.md' ] 9 | workflow_dispatch: 10 | 11 | permissions: 12 | contents: write 13 | 14 | concurrency: 15 | group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | deploy: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v3 23 | with: 24 | fetch-depth: 0 25 | - name: Determine current mdbook version 26 | id: mdbook-version 27 | uses: pozetroninc/github-action-get-latest-release@06da55dc399d06375d2d1fe57542398d5bd989c6 28 | with: 29 | owner: rust-lang 30 | repo: mdBook 31 | excludes: prerelease, draft 32 | - name: Cache mdbook 33 | id: cache-mdbook 34 | uses: actions/cache@v3 35 | with: 36 | path: ~/.cargo/bin/mdbook 37 | key: ${{ runner.os }}-mdbook-${{ steps.mdbook-version.outputs.release }} 38 | - name: Install mdbook 39 | if: steps.cache-mdbook.outputs.cache-hit != 'true' 40 | run: | 41 | curl --proto '=https' --tlsv1.2 -sSf https://rossmacarthur.github.io/install/crate.sh | bash -s -- --repo "rust-lang/mdBook" --bin mdbook --to ~/.cargo/bin 42 | - name: Determine current mdbook-toc version 43 | id: mdbook-toc-version 44 | uses: pozetroninc/github-action-get-latest-release@06da55dc399d06375d2d1fe57542398d5bd989c6 45 | with: 46 | owner: badboy 47 | repo: mdbook-toc 48 | excludes: prerelease, draft 49 | - name: Cache mdbook-toc 50 | id: cache-mdbook-toc 51 | uses: actions/cache@v3 52 | with: 53 | path: ~/.cargo/bin/mdbook-toc 54 | key: ${{ runner.os }}-mdbook-toc-${{ steps.mdbook-toc-version.outputs.release }} 55 | - name: Install mdbook-toc 56 | if: steps.cache-mdbook-toc.outputs.cache-hit != 'true' 57 | run: | 58 | curl --proto '=https' --tlsv1.2 -sSf https://rossmacarthur.github.io/install/crate.sh | bash -s -- --repo "badboy/mdbook-toc" --to ~/.cargo/bin 59 | - name: Substituting KWEB_VERSION 60 | run: | 61 | cd docs 62 | V=$(curl --silent "https://api.github.com/repos/kwebio/kweb-core/releases" | jq -r '.[0].tag_name') 63 | echo "Substituting version $V" 64 | sed -i "s/KWEB_VERSION/$V/g" src/gettingstarted.md 65 | - name: Build MDBook 66 | run: | 67 | mdbook --version 68 | mdbook-toc --version 69 | cd docs 70 | mdbook build 71 | - name: Validate hyperlinks 72 | uses: untitaker/hyperlink@0.1.26 73 | with: 74 | args: docs/book --sources src/ 75 | - name: Deploy 76 | uses: JamesIves/github-pages-deploy-action@v4 77 | with: 78 | branch: gh-pages 79 | folder: docs/book 80 | target-folder: book 81 | -------------------------------------------------------------------------------- /.github/workflows/pages.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy static content to Pages 3 | 4 | on: 5 | workflow_run: 6 | workflows: ["Build, test, and deploy docs", "Generate User Manual", "Measure unit test coverage"] 7 | types: 8 | - completed 9 | 10 | # Allows you to run this workflow manually from the Actions tab 11 | workflow_dispatch: 12 | 13 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 14 | permissions: 15 | contents: read 16 | pages: write 17 | id-token: write 18 | 19 | # Allow one concurrent deployment 20 | concurrency: 21 | group: "pages" 22 | # Set to false by @sanity because cancellations are reported as failures 23 | # which is annoying. 24 | cancel-in-progress: false 25 | 26 | jobs: 27 | # Single deploy job since we're just deploying 28 | deploy: 29 | environment: 30 | name: github-pages 31 | url: ${{ steps.deployment.outputs.page_url }} 32 | runs-on: ubuntu-latest 33 | steps: 34 | - name: Checkout 35 | uses: actions/checkout@v3 36 | with: 37 | ref: gh-pages 38 | - name: Setup Pages 39 | uses: actions/configure-pages@v2 40 | - name: Upload artifact 41 | uses: actions/upload-pages-artifact@v1 42 | with: 43 | # Upload entire repository 44 | path: '.' 45 | - name: Deploy to GitHub Pages 46 | id: deployment 47 | uses: actions/deploy-pages@v1 48 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-maven-central.yml: -------------------------------------------------------------------------------- 1 | name: "Publish to Maven Central" 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [published] 7 | 8 | concurrency: 9 | group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' 10 | cancel-in-progress: true 11 | 12 | env: 13 | SONATYPE_USERNAME: ${{ secrets.OSSRHUSERNAME }} 14 | SONATYPE_PASSWORD: ${{ secrets.OSSRHPASSWORD }} 15 | ORG_GRADLE_PROJECT_ossrhUsername: ${{ secrets.OSSRHUSERNAME }} 16 | ORG_GRADLE_PROJECT_ossrhPassword: ${{ secrets.OSSRHPASSWORD }} 17 | ORG_GRADLE_PROJECT_signingKeyId: ${{ secrets.SIGNINGKEYID }} 18 | ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNINGKEY }} 19 | ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNINGPASSWORD }} 20 | 21 | jobs: 22 | publish: 23 | name: Build and Publish to Sonatype 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v3 27 | with: 28 | fetch-depth: 0 29 | 30 | - name: Set up JDK 17 31 | uses: actions/setup-java@v3 32 | with: 33 | distribution: temurin 34 | java-version: 17 35 | 36 | - name: Setup Gradle 37 | uses: gradle/gradle-build-action@v2 38 | 39 | - name: Build and run tests 40 | run: ./gradlew build 41 | 42 | - name: Publish to Sonatype 43 | run: | 44 | VERSION=$(git tag --sort=committerdate | tail -1) 45 | echo Publishing $VERSION to Sonatype 46 | ./gradlew -Pversion=$VERSION publish 47 | 48 | ## Couldn't get this working yet, need to get the SONATYPE_REPOSITORY_ID from output of publish step. For now 49 | ## closing and release will need to be manual. 50 | # release: 51 | # name: Close and Release Sonatype staging repository 52 | # runs-on: ubuntu-latest 53 | # needs: [test, publish] 54 | # if: ${{ always() && needs.test.result == 'success' && needs.publish.result == 'success' }} 55 | # steps: 56 | # - name: Release 57 | # uses: nexus-actions/release-nexus-staging-repo@f2b4c7f64ecec2cb0d24349182c1bbeda5c4c056 58 | # with: 59 | # base_url: https://s01.oss.sonatype.org/service/local/ 60 | # username: ${{ secrets.OSSRHUSERNAME }} 61 | # password: ${{ secrets.OSSRHPASSWORD }} 62 | # staging_repository_id: no ${{ secrets.SONATYPE_REPOSITORY_ID }} 63 | # description: Closed ${{ github.repository }}#${{ github.run_number }} 64 | # close_only: false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | docs/book/** 2 | 3 | # Created by https://www.gitignore.io/api/intellij,java 4 | 5 | ### Intellij ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff: 10 | .idea/workspace.xml 11 | .idea/tasks.xml 12 | .idea/dictionaries 13 | .idea/vcs.xml 14 | .idea/jsLibraryMappings.xml 15 | 16 | # Sensitive or high-churn files: 17 | .idea/dataSources.ids 18 | .idea/dataSources.xml 19 | .idea/dataSources.local.xml 20 | .idea/sqlDataSources.xml 21 | .idea/dynamic.xml 22 | .idea/uiDesigner.xml 23 | 24 | # Gradle: 25 | .idea/gradle.xml 26 | .idea/libraries 27 | 28 | # Mongo Explorer plugin: 29 | .idea/mongoSettings.xml 30 | 31 | ## File-based project format: 32 | *.iws 33 | 34 | ## Plugin-specific files: 35 | 36 | # IntelliJ 37 | /out/ 38 | 39 | # mpeltonen/sbt-idea plugin 40 | .idea_modules/ 41 | 42 | # JIRA plugin 43 | atlassian-ide-plugin.xml 44 | 45 | # Crashlytics plugin (for Android Studio and IntelliJ) 46 | com_crashlytics_export_strings.xml 47 | crashlytics.properties 48 | crashlytics-build.properties 49 | fabric.properties 50 | 51 | ### Intellij Patch ### 52 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 53 | 54 | # *.iml 55 | # modules.xml 56 | # .idea/misc.xml 57 | # *.ipr 58 | 59 | 60 | ### Java ### 61 | *.class 62 | 63 | # Mobile Tools for Java (J2ME) 64 | .mtj.tmp/ 65 | 66 | # Package Files # 67 | *.jar 68 | *.war 69 | *.ear 70 | 71 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 72 | hs_err_pid* 73 | 74 | .idea/ 75 | build/ 76 | .gradle/ 77 | !/gradle/wrapper/gradle-wrapper.jar 78 | 79 | classes/ 80 | 81 | docs/_site 82 | 83 | data/ 84 | 85 | .kotlintest 86 | phantomjsdriver.log 87 | 88 | # used to clean up the logs while working on kweb 89 | src/main/resources/logback.xml 90 | 91 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Kweb Code of Conduct 2 | 3 | Treat others as you would like to be treated yourself. 4 | -------------------------------------------------------------------------------- /DEVELOPER.md: -------------------------------------------------------------------------------- 1 | # Developer Notes 2 | 3 | ## Recommended setup 4 | 5 | ### Git hooks 6 | 7 | We recommend using this for `.git/hooks/pre-commit`: 8 | 9 | ```bash 10 | #!/bin/bash 11 | 12 | ./gradlew test 13 | ``` 14 | 15 | ## apiDump 16 | 17 | Kweb's external API will be checked against `api/kweb-core.api` and the build will fail if it changes. This will 18 | often have false-positives so to update the API dump, run `./gradlew apiDump` and commit the new dump file 19 | with your other changes. 20 | 21 | ## Updating the user manual 22 | 23 | You can build the user manual locally by [installing mdBook](https://rust-lang.github.io/mdBook/guide/installation.html) 24 | and running `mdbook serve` in the `docs/` directory. You can then view the documentation at http://localhost:3000/, 25 | changes will be automatically reloaded. -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | `kotlin-dsl` 5 | kotlin("jvm") version embeddedKotlinVersion 6 | } 7 | 8 | repositories { 9 | gradlePluginPortal() 10 | } 11 | 12 | dependencies { 13 | implementation(platform(kotlin("bom"))) 14 | 15 | // Import Gradle Plugins that will be used in the buildSrc pre-compiled script plugins, and any `build.gradle.kts` 16 | // files in the project. 17 | // Use their Maven coordinates (plus versions), not Gradle plugin IDs! 18 | // This should be the only place that Gradle plugin versions are defined, so they are aligned across all build scripts 19 | implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22") 20 | implementation("org.jetbrains.kotlin:kotlin-serialization:1.9.22") 21 | } 22 | 23 | val gradleJvmTarget = 17 24 | 25 | kotlin { 26 | jvmToolchain { 27 | (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(gradleJvmTarget)) 28 | } 29 | } 30 | 31 | kotlinDslPluginOptions { 32 | jvmTarget.set("$gradleJvmTarget") 33 | } 34 | 35 | tasks.withType().configureEach { 36 | kotlinOptions { 37 | jvmTarget = "$gradleJvmTarget" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /buildSrc/repositories.settings.gradle.kts: -------------------------------------------------------------------------------- 1 | // Centralized Repository configuration, that will be shared between both buildSrc and the root project 2 | 3 | @Suppress("UnstableApiUsage") // Central declaration of repositories is an incubating feature 4 | dependencyResolutionManagement { 5 | 6 | repositories { 7 | mavenCentral() 8 | jitpack() 9 | gradlePluginPortal() 10 | } 11 | 12 | pluginManagement { 13 | repositories { 14 | gradlePluginPortal() 15 | mavenCentral() 16 | jitpack() 17 | } 18 | } 19 | } 20 | 21 | fun RepositoryHandler.jitpack() { 22 | maven("https://jitpack.io") 23 | } 24 | -------------------------------------------------------------------------------- /buildSrc/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "buildSrc" 2 | 3 | apply(from = "./repositories.settings.gradle.kts") 4 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/buildsrc/conventions/base.gradle.kts: -------------------------------------------------------------------------------- 1 | package buildsrc.conventions 2 | 3 | plugins { 4 | base 5 | } 6 | 7 | description = "common Gradle configuration that should be applied to all projets" 8 | 9 | if (project != rootProject) { 10 | version = rootProject.version 11 | group = rootProject.group 12 | } 13 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/buildsrc/conventions/kotlin-jvm.gradle.kts: -------------------------------------------------------------------------------- 1 | package buildsrc.conventions 2 | 3 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 4 | 5 | plugins { 6 | id("buildsrc.conventions.base") 7 | kotlin("jvm") 8 | } 9 | 10 | val projectJvmVersion = 17 11 | 12 | tasks.withType().configureEach { 13 | kotlinOptions { 14 | jvmTarget = "$projectJvmVersion" 15 | } 16 | } 17 | 18 | tasks.withType().configureEach { 19 | useJUnitPlatform() 20 | } 21 | -------------------------------------------------------------------------------- /docs/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Ian Clarke"] 3 | description = "User manual for the Kweb web framework" 4 | language = "en" 5 | multilingual = false 6 | src = "src" 7 | title = "The Kweb User Manual" 8 | 9 | [preprocessor.toc] 10 | command = "mdbook-toc" 11 | renderer = ["html"] 12 | 13 | [output.html] 14 | git-repository-url = "https://github.com/kwebio/kweb-core" 15 | edit-url-template = "https://github.com/kwebio/kweb-core/edit/master/docs/{path}" 16 | site-url = "/book/" -------------------------------------------------------------------------------- /docs/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Introduction](intro.md) 4 | - [Getting Started](gettingstarted.md) 5 | - [DOM Basics](dom.md) 6 | - [Event Handling](events.md) 7 | - [Observer Pattern & State](state.md) 8 | - [URL Routing](routing.md) 9 | - [CSS & Style](style.md) 10 | - [Components](components.md) 11 | - [JavaScript Interop](js.md) 12 | - [Speed & Efficiency](speed.md) 13 | - [FAQ](faq.md) 14 | -------------------------------------------------------------------------------- /docs/src/components.md: -------------------------------------------------------------------------------- 1 | # Components 2 | 3 | 4 | 5 | ## Managing Complexity 6 | 7 | Composable components help manage software complexity by allowing developers to break down 8 | a complex problem into smaller, more manageable pieces. Other benefits include 9 | reusability, testability, and the ability to reason about a system in isolation. 10 | 11 | ## The Component typealias 12 | 13 | We rely on a small amount of syntactic sugar defined in [kweb.components.Component](https://docs.kweb.io/api/kweb-core/kweb.components.html#7274344%2FClasslikes%2F769193423): 14 | 15 | ```kotlin 16 | typealias Component = ElementCreator<*> 17 | ``` 18 | 19 | And then we can use an extension function on this to create a component: 20 | 21 | ```kotlin 22 | {{#include ../../src/test/kotlin/kweb/docs/components.kt:simple_component}} 23 | ``` 24 | 25 | And we use the component like this: 26 | 27 | ```kotlin 28 | {{#include ../../src/test/kotlin/kweb/docs/components.kt:component_usage}} 29 | ``` 30 | 31 | Components are configured through the extension function parameters, typically through 32 | a mixture of: 33 | 34 | | Parameter Type | For | 35 | |----------------------------------------------------------------------------------------------|-----------------------------------------------------------------| 36 | | [KVal](https://docs.kweb.io/api/kweb-core/kweb.state/-k-val/index.html)s | Values that can change but not be modified by the component | 37 | | [KVar](https://docs.kweb.io/api/kweb-core/kweb.state/-k-var/index.html)s | Values that can change or be modified by the component | 38 | | [ObservableList](https://docs.kweb.io/api/kweb-core/kweb.state/-observable-list/index.html)s | Lists of values that can change or be modified by the component | 39 | | Double, String, etc | Values that don't change | 40 | 41 | The simplest Component's may have no parameters at all, or just one or two, while the most complex might use 42 | a [DSL builder](https://in-kotlin.com/design-patterns/builder-pattern/dsl/). 43 | 44 | ## A more complex example 45 | 46 | In this example we create a **Component** that wraps an [\ element](https://bulma.io/documentation/form/input/) 47 | styled using the [Bulma CSS framework](https://bulma.io/): 48 | 49 | ```kotlin 50 | {{#include ../../src/test/kotlin/kweb/docs/components.kt:bulma_component_example}} 51 | ``` 52 | 53 | This component can then be used like this: 54 | 55 | ```kotlin 56 | {{#include ../../src/test/kotlin/kweb/docs/components.kt:bulma_component_usage}} 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/src/dom.md: -------------------------------------------------------------------------------- 1 | # DOM Basics 2 | 3 | ## Table of Contents 4 | 5 | 6 | 7 | ## Creating DOM Elements and Fragments 8 | 9 | Let's create a `