Skip to content

DataDink/webtini

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

95 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

webtini

minimalistic view modeling for the web

similarities to knockout and vue but smaller and rawer

  • Minimalistic
  • Conformant
  • Declarative
  • Unobtrusive
  • Modular

Quick Start

the modern web doesn't need to be obfuscated and transpiled

<html>
  <head>
    <title>webtini quick-start</title>
    <script src="https://datadink.github.io/webtini/packages/standard-binder-package.min.js"></script>
    <!-- A style to hide the page until its ready -->
    <style>.loading { display: none; }</style>
  </head>
  <!-- Binds the "loading" class to the isLoading property on the Application -->
  <body class="loading" bind-class-loading="isLoading">
    <header>
      <!-- Binds to the "title" property on the application -->
      <h1>{title}</h1>
    </header>
    <nav>
      <!-- Binds this template to the `links` array on the Application -->
      <!-- Each item in the `links` array will generate an instance of the template content -->
      <template bind="links">
        <li><a bind-href="url">{text}</a></li>
      </template>
    </nav>
    <h1>Count: {count}</h1>
    <!-- Binds the button's "click" event to the "increment" function on the application -->
    <button bind-event-click="increment">Increment</button>
    <!-- Binds the input's "value" property to the application's "count" property -->
    <!-- Binds the input's "input" event to the application's "oninput" function -->
    <input type="number" bind-value="count" bind-event-input="oninput">
    <div>
      <!-- Binds this template to the "items" array on the Application -->
      <!-- Note: Each item is bound to Application.items[x]
        `~` binds the data root (Application)
        `^` binds the parent (Applications.items)
        `^.^` binds the parent-parent (Application)
      -->
      <template bind="items">
        <span>{{{value} of {^.length} or {~.count}/{^.^.count}}}</span>
      </template>
    </div>
    <script type="module">
      // The Application here acts as a viewmodel that the DOM view can be bound to using a `Binder`.
      // It exposes data and functionality for the view to bind to.
      class Application {
        // Binders are the engines for webtini applications.
        binder = new webtini.StandardBinder();

        // The body's "loading" class is bound to this value
        isLoading = false; 

        // The heading is bound to this value which pulls from the <title> in the header
        get title() { return document.querySelector('title').textContent; }

        // The page navigation template binds here and generates an instance of its content
        // for each item.
        links = [
          { text: 'source',  url: 'https://github.com/datadink/webtini' },
          { text: 'documentation',  url: 'https://datadink.github.io/webtini/documentation' },
        ];

        // A coordinated data value that multiple parts of the application use
        count = 0;

        // An event handler that triggers when the button in the view is clicked
        increment() { 
          this.count++; 
          this.render();
        }

        // An event handler that triggers when the input in the view is altered
        // Warning: Be aware of handlers that trigger events that retrigger handlers -> infinite recursion
        oninput(e) { 
          this.count = parseInt(e.target.value ?? 0); 
          this.render();
        }

        // (Advanced) Creates an array of items based on the "count" that a template in the view binds to.
        get items() { 
          var number = Math.abs(Math.max(-5000, Math.min(100, this.count)));
          return [...new Array(Number.isNaN(number) ? 0 : number)]
            .map((_, i) => ({ value: i + 1 })); 
        }

        // Triggers the binder on the body of this page to (re)render the page with the application's data
        render() { this.binder.bind(document.body, this); }
      }
      const app = new Application();
      app.render();
    </script>
  </body>
</html>

Packages

use the web as-is and as it's meant to be

Standard

Includes all standard modules

download

Common JS

<script src="standard-binder-package.min.js"></script>
const binder = new webtini.StandardBinder();

JS Module

import {StandardBinder} from './standard-binder-module.min.js';
const binder = new StandardBinder();

Includes:

  • AttributeBinder
  • ClassBinder
  • EventBinder
  • StyleBinder
  • TemplateBinder
  • TextBinder

Minimal

Provides basic model binding, content generation & interactivity

download

Common JS

<!-- to pull directly from github (not for production) -->
<script src="minimal-binder-package.min.js"></script>
const binder = webtini.MinimalBinder();

JS Module

// to import directly from github (also not for production)
import {MinimalBinder} from './minimal-binder-module.min.js';
const binder = new MinimalBinder();

Includes:

  • TemplateBinder
  • EventBinder

Basic Binders

webtini is modular & extensible - use as much or little as you like

AttributeBinder

Enables bind-attribute-name attributes to bind values to other attributes on an element

<img bind-attribute-alt="data.context.text" />

ClassBinder

Enables bind-class-name attributes to toggle classes on an element from a boolean(ish) value

<div bind-class-active="data.context.selected">...</div>

EventBinder

Enables bind-event-name attributes to assign functions to events on an element

<button bind-event-click="data.context.submit">Save</button>

StyleBinder

Enables bind-style-name attributes to assign values to an element's styles

<div bind-style-background="data.context.color">...</div>

TemplateBinder

Causes HTMLTemplateElements to generate content when bound to an array

<template bind="data.context.items"><span bind-textcontent="name"></span></template>
binder.bind(element, { data: { context: { items: [{name: 'a'}, {name: 'b'}] } } });

TextBinder

Enables familiar inline {data.property} binding from within text.

<h1>Page: {title}</h1>

FAQ

constomize webtini to work the way you want

  • When does it make sense to use this?
    • When you need a web app right now with little effort and no overhead.
  • What is the benefit?
    • This package helps to keep web development simple, clean and extensible.
    • Modern web technologies no longer need massive processing efforts such as transpiling from something else.
    • By working with & along-side modern web patterns & practices it is easier to prevent your code from becoming obsolete.
    • MVVM and similar patterns help keep concerns decoupled and modular.
  • Can this be used for large applications?
    • Yes.
  • Does this work on legacy browsers?
    • No: webtini targets modern browsers only
  • Is it performant?
    • Depends: webtini leaves performance up to you. You have full control over the render/update loop, etc.
    • Typically, web applications do not need extreme performance and there's no framework in the world that doesn't add overhead to your application.
  • Does it scale?
    • Depends: webtini only focuses on connecting your view with your data & functionality. The scalability of the app you write is up to you.
    • Because of webtini's extensible design, it can be easily customized, optimized and you can even contribute here if you've got something useful!
  • What do I have to learn?
    • Just good-ol', raw javascript, html, and css.
    • Understanding data-driven patterns like MVVM will help a lot.
  • Can I use typescript?
    • As far as I know.
  • How does this fit in with REACT?
    • It doesn't. React obfuscates and entangles web technologies. webtini embraces them.

Releases

No releases published

Packages

No packages published