HTML Framework that allows you not to write JavaScript code.

Overview

NPM Version Build Status

EHTML (or Extended HTML) can be described as a set of custom elements that you can put on HTML page for different purposes and use cases. The main idea and goal of this library is to provide a convenient way to get rid of JavaScript code on the client side as much as it's possible for basic and routine stuff.

Disclaimer: "I cannot build complex things with EHTML yet, but I can build simple things with it so easily that no other library can do."

Contents

Usage

EHTML is very easy to include in your project. Save this file locally and use it:

<head>
  <script src="/../js/ehtml.bundle.min.js" type="text/javascript"></script>
</head>

Introduction Video

Simple EHTML Blog App

IMAGE ALT TEXT HERE

Supported elements

E-HTML

Sometimes html files can be very big, so why not just split them into different smaller html files and put sort of links to them in the main html file? e-html allows you to do that by introducing a module system in HTML.

So, let's say we have main articles.html file

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">

  <head>
    <link rel="shortcut icon" href="/../images/favicon.ico"/>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>e-html</title>
    <link rel="stylesheet" href="/../css/main.css">
    <script src="/../js/ehtml.bundle.min.js" type="text/javascript"></script>
  </head>

  <body class="main">
    <div class="articles">

      <e-html data-src="/../html/first.html"></e-html>
      <e-html data-src="/../html/second.html"></e-html>
      <e-html data-src="/../html/third.html"></e-html>

    </div>
  </body>

</html>

and as you can see, we have three e-html tags here. And each of them refers to some html file which contains some part of the article.hmtl. This tag has only one custom attribute data-src, which tells us where exactly the file that we want to include is served.

And for example, first.html would look something like this

<div class="article">
  <!-- some content of the first article -->
</div>

And when you open articles.html in a browser, it will be rendered as if you included all the parts in one file:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">

  <head>
    <link rel="shortcut icon" href="/../images/favicon.ico"/>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>e-html</title>
    <link rel="stylesheet" href="/../css/main.css">
    <script src="/../js/ehtml.bundle.min.js" type="text/javascript"></script>
  </head>

  <body class="main">
    <div class="articles">

      <div class="article">
        <!-- content of the first article -->
      </div>
      <div class="article">
        <!-- content of the second article -->
      </div>
      <div class="article">
        <!-- content of the third article -->
      </div>

    </div>
  </body>

</html>

The main benefit of using this element is that you can much more easily modify your big html files. So, instead of having one big html file where you have to find a specific part of it to modify, you can just find a file, which contains this specific part and make changes there.

Of course, this element makes an additional http(s) request for fetching a specific part, but you can always cache the files, so it would not cause any performance issues.

E-JSON

e-json allows you to fetch json resource by GET request from the server and apply some actions on the response. So, for example, let's say you have an endpoint /album/{title}, which returns following response:

title = 'Humbug'
{
  "title": "Humbug",
  "artist": "Arctic Monkeys",
  "type": "studio album",
  "releaseDate": "19 August 2009",
  "genre": "psychedelic rock, hard rock, stoner rock, desert rock",
  "length": "39:20",
  "label": "Domino",
  "producer": "James Ford, Joshua Homme"
}

Then you can fetch it via e-json like in following html code:

<e-json
  data-src="/../album/Humbug"
  data-response-name="albumResponse"
  data-actions-on-response="
    mapToTemplate('${albumResponse.body}', '#album-info');
  ">

  <template id="album-info" data-object-name="album">
    <div data-text="Title: ${album.title}"></div>
    <div data-text="Artist: ${album.artist}"></div>
    <div data-text="Type: ${album.type}"></div>
    <div data-text="Release date: ${album.releaseDate}"></div>
    <div data-text="Genre: ${album.genre}"></div>
    <div data-text="Length: ${album.length}"></div>
    <div data-text="Label: ${album.label}"></div>
    <div data-text="Producer: ${album.producer}"></div>
  </template>
</e-json>

So, e-json has attributes data-src which tells us where from we can fetch json response. Attribute data-response-name specifies the name that we want to use for the response. It contains body, statusCode and headers properties, so you can use them in the attribute data-actions-on-response. In this case we just decided to map body of our response to the element with id album-info, which also must have the attribute data-object-name. This attribute specifies the name of the object that we want to map. It's important to mention that you can map object only to <template>, which is in e-json that provides the object for mapping. More details about actions on response you can find in this section.

If you need some request headers, you can specify them in the attribute data-request-headers with format { "headerName": "headerValue", ... }.

You can also add attributes data-ajax-icon and data-progress-bar as element selectors for presenting progress of fetching data from the server. You can see how to use them in the examples.

E-JSON template (v1.0.12)

You can use e-json as a <template> element, if you just need to map response.

title = 'Humbug'
{
  "title": "Humbug",
  "artist": "Arctic Monkeys",
  "type": "studio album",
  "releaseDate": "19 August 2009",
  "genre": "psychedelic rock, hard rock, stoner rock, desert rock",
  "length": "39:20",
  "label": "Domino",
  "producer": "James Ford, Joshua Homme"
}
<template is="e-json" data-src="/../album/Humbug" data-object-name="albumResponse">
  <div data-text="Title: ${albumResponse.body.title}"></div>
  <div data-text="Artist: ${albumResponse.body.artist}"></div>
  <div data-text="Type: ${albumResponse.body.type}"></div>
  <div data-text="Release date: ${albumResponse.body.releaseDate}"></div>
  <div data-text="Genre: ${albumResponse.body.genre}"></div>
  <div data-text="Length: ${albumResponse.body.length}"></div>
  <div data-text="Label: ${albumResponse.body.label}"></div>
  <div data-text="Producer: ${albumResponse.body.producer}"></div>
</template>

Here you don't use data-response-name attribute as you don't need apply actions on response via data-actions-on-response attribute. But you still have to specify data-object-name to define a variable for the response, so you can use it as a mapping object inside of e-json template.

And as for simple e-json you can also add attributes data-ajax-icon and data-progress-bar as element selectors for presenting progress of fetching data from the server. You can see how to use them in the examples.

E-FOR-EACH template

You can use standard template html element with attribute is="e-for-each" for iterating some object for mapping to an element. So, let's say you have an endpoint /album/{title}/songs, which returns following response:

title = 'Humbug'
{
  "title": "Humbug",
  "artist": "Arctic Monkeys",
  "songs": [
    { "title": "My Propeller", "length": "3:27" },
    { "title": "Crying Lightning", "length": "3:43" },
    { "title": "Dangerous Animals", "length": "3:30" },
    { "title": "Secret Door", "length": "3:43" },
    { "title": "Potion Approaching", "length": "3:32" },
    { "title": "Fire and the Thud", "length": "3:57" },
    { "title": "Cornerstone", "length": "3:18" },
    { "title": "Dance Little Liar", "length": "4:43" },
    { "title": "Pretty Visitors", "length": "3:40" },
    { "title": "The Jeweller's Hands", "length": "5:42" }
  ]
}

Then your html code would be something like this:

<e-json
  data-src="/../album/Humbug/songs"
  data-response-name="albumResponse"
  data-actions-on-response="
    mapToTemplate('${albumResponse.body}', '#album-info');
  ">

  <template id="album-info" data-object-name="album">

    <div data-text="Title: ${album.title}"></div>
    <div data-text="Artist: ${album.artist}"></div>

    <div><b data-text="${album.songs.length} songs:"></b></div>
    <template is="e-for-each" data-list-to-iterate="${album.songs}" data-item-name="song">
      <div class="song-box">
        <div data-text="No. ${song.index}/${album.songs.length}"></div>
        <div data-text="Title: ${song.title}"></div>
        <div data-text="Length: ${song.length}"></div>
      </div>
    </template>

  </template>
</e-json>

So, as you can see it's pretty straightforward: e-for-each template has attribute data-list-to-iterate where you can specify the list from the mapped object that you want to iterate. And attribute data-item-name specifies the name of the item that you want to map to the template. You can also use index property of the item in the mapping which starts from 1.

When you open a browser, template will be replaced with its n times duplicated inner content for each item, where n is the length of the list that has been iterated:

<e-json
  data-src="/../album/Humbug/songs"
  data-response-name="albumResponse"
  data-actions-on-response="
    mapToTemplate('${albumResponse.body}', '#album-info');
  ">

  <div>Title: Humbug</div>
  <div>Artist: Arctic Monkeys</div>

  <div><b>10 songs:</b></div>
  <div class="song-box">
    <div>No. 1/10</div>
    <div>Title: My Propeller</div>
    <div>Length: 3:27</div>
  </div>
  <div class="song-box">
    <div>No. 2/10</div>
    <div>Title: Crying Lightning</div>
    <div>Length: 3:43</div>
  </div>
  <div class="song-box">
    <div>No. 3/10</div>
    <div>Title: Dangerous Animals</div>
    <div>Length: 3:30</div>
  </div>
  <div class="song-box">
    <div>No. 4/10</div>
    <div>Title: Secret Door</div>
    <div>Length: 3:43</div>
  </div>
  <div class="song-box">
    <div>No. 5/10</div>
    <div>Title: Potion Approaching</div>
    <div>Length: 3:32</div>
  </div>
  <div class="song-box">
    <div>No. 6/10</div>
    <div>Title: Fire and the Thud</div>
    <div>Length: 3:57</div>
  </div>
  <div class="song-box">
    <div>No. 7/10</div>
    <div>Title: Cornerstone</div>
    <div>Length: 3:18</div>
  </div>
  <div class="song-box">
    <div>No. 8/10</div>
    <div>Title: Dance Little Liar</div>
    <div>Length: 4:43</div>
  </div>
  <div class="song-box">
    <div>No. 9/10</div>
    <div>Title: Pretty Visitors</div>
    <div>Length: 3:40</div>
  </div>
  <div class="song-box">
    <div>No. 10/10</div>
    <div>Title: The Jeweller's Hands</div>
    <div>Length: 5:42</div>
  </div>

</e-json>
E-IF template

This standard template html element with attribute is="e-if" decides if some particular part of html needs to be displayed or not while mapping some object to an element. So, let's say you have an endpoint /album/{title}/songs, which returns following response:

title = 'Humbug'
{
  "title": "Humbug",
  "artist": "Arctic Monkeys",
  "songs": [
    { "title": "My Propeller", "length": "3:27" },
    { "title": "Crying Lightning", "length": "3:43" },
    { "title": "Dangerous Animals", "length": "3:30" },
    { "title": "Secret Door", "length": "3:43" },
    { "title": "Potion Approaching", "length": "3:32" },
    { "title": "Fire and the Thud", "length": "3:57" },
    { "title": "Cornerstone", "length": "3:18" },
    { "title": "Dance Little Liar", "length": "4:43" },
    { "title": "Pretty Visitors", "length": "3:40" },
    { "title": "The Jeweller's Hands", "length": "5:42" }
  ]
}

And you would like to display only songs that shorter than '3:30' in length. Then your html code would be something like this:

<e-json
  data-src="/../album/Humbug/songs"
  data-response-name="albumResponse"
  data-actions-on-response="
    mapToTemplate('${albumResponse.body}', '#album-info');
  ">

  <template id="album-info" data-object-name="album">

    <div data-text="Title: ${album.title}"></div>
    <div data-text="Artist: ${album.artist}"></div>

    <div><b>Songs that shorter than 3:30:</b></div>
    <template is="e-for-each" data-list-to-iterate="${album.songs}" data-item-name="song">

      <template is="e-if"
        data-condition-to-display="${(song.length.split(':')[0] * 60 + song.length.split(':')[1] * 1) <= 210}"
      >
        <div class="song-box">
          <div data-text="No. ${song.index}/${album.songs.length}"></div>
          <div data-text="Title: ${song.title}"></div>
          <div data-text="Length: ${song.length}"></div>
        </div>
      </template>
    
    </template>

  </template>
</e-json>

This element has only one attribute data-condition-to-display that specifies a condition whether inner content of the template has to be displayed.

When you open a browser, you will see:

<e-json
  data-src="/../album/Humbug/songs"
  data-response-name="albumResponse"
  data-actions-on-response="
    mapToTemplate('${albumResponse.body}', '#album-info');
  ">

  <div>Title: Humbug</div>
  <div>Artist: Arctic Monkeys</div>

  <div><b>Songs that shorter than 3:30:</b></div>
  <div class="song-box">
    <div>No. 1/10</div>
    <div>Title: My Propeller</div>
    <div>Length: 3:27</div>
  </div>
  <div class="song-box">
    <div>No. 3/10</div>
    <div>Title: Dangerous Animals</div>
    <div>Length: 3:30</div>
  </div>
  <div class="song-box">
    <div>No. 7/10</div>
    <div>Title: Cornerstone</div>
    <div>Length: 3:18</div>
  </div>

</e-json>
E-FORM

Custom element e-form is a great solution, if you want to send data from your form in JSON format. So, let's say you have an endpoint /artist/{name}/albums/add with method 'POST' and expected request body is something like:

name = 'Arctic Monkeys'
{
  "title": "Humbug",
  "type": "studio album",
  "releaseDate": "19 August 2009",
  "genre": ["psychedelic rock", "hard rock", "stoner rock", "desert rock"],
  "length": "39:20",
  "label": "Domino",
  "producer": "James Ford, Joshua Homme"
}

Then you can make this request with following html code:

<e-form>
  
  Title:
  <input type="text" name="title">
  
  Type:
  <input type="radio" name="type" value="studio album" checked>
  <label for="one">One</label>

  <input type="radio" name="type" value="live album" checked>
  <label for="one">One</label>

  Release date:
  <input type="date" name="releaseDate">

  Genre:
  <input type="checkbox" name="genre" value="psychedelic rock">
  <input type="checkbox" name="genre" value="hard rock">
  <input type="checkbox" name="genre" value="stoner rock">
  <input type="checkbox" name="genre" value="desert rock">

  Total length:
  <input type="time" name="totalLength">

  Producer:
  <input type="text" name="producer">

  <button
    id="send"
    data-request-url="/artist/Arctic_Monkeys/albums/add"
    data-request-method="POST"
    data-request-headers="{}"
    data-ajax-icon="#ajax-icon"
    data-response-name="savedAlbum"
    onclick="this.form.submit(this)"
    data-actions-on-response="
      logToConsole('response: ', '${savedAlbum}');
    "
  />

  <img id="ajax-icon" src="/../images/ajax-loader.gif"/>
  
</e-form>

So, like standard form element e-form can have inputs with different types, selects, radio buttons, checkboxes and textareas. Every item in e-form mast have name attribute, which will be used as a key in the request body. And value of every item is used as a value for corresponding name in the request body.

This element will be rendered as a standard form element with attribute data-e-form="true", but it will send its data as json object. You can do it by attaching events on buttons or other active elements with function: this.form.submit(this), which constructs a request body by the form's items and submits it. Such approach is much better than standard action attribute in the form tag because you can attach different requests on several active elements using the same form.

Also you have to add other information about the request you want to make in the attributes: data-request-url, data-request-method, data-request-headers. You can even add attributes like data-ajax-icon, data-progress-bar and data-upload-progress-bar which can display progress of the request.

Like for e-json, you can do some actions on response with the name that you specify in data-response-name attribute. In this case, we just log the response from the request.

You can also do validation of your e-forms by attributes: required, pattern, data-validation-error-class-for-element, data-validation-error-class-for-message-box, data-validation-bad-format-error-message and data-validation-min-files-number. More details you can find in the examples.

E-REUSABLE template (v1.0.8)

You use action mapToTemplate on a template with attribute is="e-reusable", so you can map response object multiple times. Also you can specify attribute data-append-to="#someSelector" or data-prepend-to="#someSelector" to decide where and how mapped content of the template should be placed. If you don't specify one of these attributes, then mapped content of the template will be placed right before the template.

So, the main difference between "reusable" template and other types of templates is that "reusable" template is not getting removed from the DOM, so you can use it several times.

More details you cand in the examples.

E-LOCAL-STORAGE-VALUE and E-SESSION-STORAGE-VALUE

For retrieving values from local storage you can use e-local-storage-value and use it in a form:

<e-form>
  
  <e-local-storage-value name="jwt" data-key="jwtToken"></e-local-storage-value>

  <button
    id="send"
    data-request-url="/verify"
    data-request-method="POST"
    data-request-headers="{}"
    data-ajax-icon="#ajaxIcon"
    data-response-name="response"
    onclick="this.form.submit(this)"
    data-actions-on-response="
      logToConsole('response: ', '${response}');
    "
  />

  <img id="ajaxIcon" src="/../images/ajax-loader.gif"/>
  
</e-form>

Element e-local-storage-value behaves like any input element in the e-form: it has attribute name which will be used as a key in request body, and value of the e-local-storage-value is a value that is stored in the local storage with the key that you specify in the data-key attribute.

So, in this case e-form will construct following request body:

{
  "jwt": "some value from local storage with key 'jwtToken' (it's like localStorage.getItem('jwtToken'))" 
}

Element e-session-storage-value works in the same way as e-local-storage-value but with session storage:

<e-form>
  
  <e-local-session-value name="sessionToken" data-key="token"></e-local-storage-value>

  <button
    id="send"
    data-request-url="/verify/"
    data-request-method="POST"
    data-request-headers="{}"
    data-ajax-icon="#ajaxIcon"
    data-response-name="response"
    onclick="this.form.submit(this)"
    data-actions-on-response="
      logToConsole('response: ', '${response}');
    "
  />

  <img id="ajaxIcon" src="/../images/ajax-loader.gif"/>
  
</e-form>
{
  "sessionToken": "some value from session storage with key 'token' (it's like sessionStorage.getItem('token'))" 
}

You can also get items from local and session storages in the attributes of any elements: some-attr="${localStorage.getItem('itemName')}" or some-attr="${sessionStorage.getItem('itemName')}".

E-GOOGLE-OAUTH-BUTTON

You can integrate Google Sign-In into your web app just by adding one button:

<e-google-oauth-button
  class="customSignIn"
  data-client-id="8310979471-lvmkisk1b33fjd25pjjqe8v8fa72rq2q.apps.googleusercontent.com"
  data-redirect-url="/../google"
  data-cookiepolicy="single_host_origin"
  data-scope="profile"
  data-request-token-key="googleToken"
  data-response-name="responseWithToken"
  data-actions-on-response="
    saveToLocalStorage('jwt', '${responseWithToken.body.jwt}');
  ">

  <span id="google-icon" class="icon"></span>
  <span class="buttonText">Sign in with Google</span>

</e-google-oauth-button>

It will be rendered as a simple button with attribute data-e-google-oauth-button="true". You can configure google oauth with custom attributes: data-client-id, data-redirect-url, data-cookiepolicy and data-scope.

Attribute data-request-token-key specifies a key in the request body that you will send to your api after it's been obtained from google endpoint. So, in this case your endpoint with path /../google(which you specified in the data-redirect-url) would expect request body: { "googleToken": "<some token from google>" }. And let's say your endpoint returns response with jwt token that's based on user data, which has been recived by "googleToken". You can use this response in attribute data-actions-on-response. For example, in this case we save it to local storage. The name of the response you specify in data-response-name like in e-json or e-form.

Demo of e-google-oauth-button you can find in the examples.

E-PAGE-WITH-URL template

You can define url parameters via template with attribute is="e-page-with-url":

<body>
  <template is="e-page-with-url" data-url-pattern="/album/{title}">
    <!-- content -->
  </template>
</body>

Or for example:

<body>
  <template is="e-page-with-url" data-url-pattern="/artists?{search}">
    <!-- content -->
  </e-page-with-url>
</body>

You can get url parameters in any attributes of any elements via urlParams object: some-attr="${urlParams.someValue}". It's important to place e-page-with-url in the beginning of <body> with all elements that use urlParams inside of it:

<body>
  <template is="e-page-with-url" data-url-pattern="/album/{title}">
    
    <div data-text="Album title: ${urlParams.title}"></div>

  </template>
</body>

So, for example, when you open url http://0.0.0.0:8000/album/Humbug in a browser, you would see:

<body>
    
  <div>Album title: Humbug</div>

</body>

Element e-page-with-url is a template because we have to initialize urlParams before we render all elements that use those parameters.

More details you can find in the examples.

E-TURBOLINK

EHTML supports turbolinks via e-turbolink. The main difference from classic turbolinks is that e-tubolink does not merge <head> from the page it fetches. The idea behind this decision was that it would make rendered html code much cleaner(but this decision is still discussable).

<e-turbolink data-href="/../html/next.html" data-ajax-favicon="/../images/ajax-loader.gif">
  next page
</e-turbolink>

e-turbolink will be rendered as a simple link <a> with attribute data-e-turbolink="true". When you click on a e-turbolink, it fetches a page which is served with the path that you specify in the attribute data-href, extracts <body> from there and swaps it with current <body>. Also it saves history, so you can use Reload, Back and Forward buttons in the browser.

As e-turbolink does not merge <head>, you have to design it in a way so it would work for every page that you want to "turbolink" there.

Also you can specify ajax favicon via attribute data-ajax-favicon, but it would probably not work in Chrome, as it does not support gif format in the favicons.

But you can use progress bars instead via data-with-progress-bar:

<e-turbolink data-href="/../html/next.html" data-with-progress-bar="progress-bar">
  next page
</e-turbolink>

where value of this attribute is a css class:

.progress-bar {
  width: 100%;
}

You can also specify a place for the progress bar via attribute data-progress-bar-place, by default it's body.

Demo of e-turbolink you can find in the examples.

E-SELECT

Standard select can be better. For example, it would be great if we could set a value to it, so it would be selected automatically on render. e-select does such thing:

<e-select
  name="color" 
  value="green">
  <option value="red" name="color">Red</option>
  <option value="green" name="color">Green</option>
  <option value="blue" name="color">Blue</option>
</e-select>

It will be rendered as a simple select with attribute data-e-select="true" with automatically selected value that you specify in attribute value.

Demo of e-select you can find in the examples.

E-GITHUB-OAUTH-BUTTON

You can integrate GitHub Sign-In into your web app just by adding one button:

<e-github-oauth-button
  class="customSignIn"
  data-client-id="9740bb12713949b1c23d"
  data-redirect-uri="http://localhost:8000/html/github.html/"
  data-scope="user,repo">
  <span id="github-icon" class="icon"></span>
  <span class="buttonText">Sign in with Github</span>
</e-github-oauth-button>

It will be rendered as a simple button with attribute data-e-github-oauth-button="true". You can configure github oauth with custom attributes: data-client-id, data-redirect-uri and data-scope.

And your page which is in redirect-uri can look like:

<!-- html/github.html -->
<body class="main">
  <template is="e-page-with-url" data-url-pattern="/html/github.html?{code}">
    <div class="base">
      <e-form
        data-request-url="/../github"
        data-request-method="POST"
        data-request-headers="{}"
        data-ajax-icon="#ajax-icon"
        data-response-name="responseWithToken"
        data-actions-on-response="
          saveToLocalStorage('jwt', '${responseWithToken.body.jwt}');
          turboRedirect('/../e-github-oauth-button.html');
      ">
        <input type="hidden" name="code" value="${urlParams.code}">
        <img id="ajax-icon" class="ajax-icon" src="/../images/ajax-icon.svg"/>
      </e-form>
    </div> 
  </template>
</body>

In the redirect uri we expect code param, which we want to retrieve via e-page-with-url template. And then using simple e-form with <input type="hidden"> we send the code in the request to our endpoint /../github, which is supposed to return response with some jwt token. After we get the jwt token, we save it into local storage and make turbo redirect to the original page where we have been redirected from. And you can notice that we use all data-request-* attributes right in the e-form. That allows us to send the form on rendering page, so we don't have to click on some button, for example.

Demo of e-github-oauth-button you can find in the examples.

E-SVG (v1.0.15)

With element e-svg you can load svg code right into your html page:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">

  <head>
    <link rel="shortcut icon" href="/../images/favicon.ico"/>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>e-html</title>
    <link rel="stylesheet" href="/../css/main.css">
    <script src="/../js/ehtml.bundle.min.js" type="text/javascript"></script>
  </head>

  <body class="main">

      <e-svg data-src="/../images/svg-from-server.svg"></e-svg>

  </body>

</html>

And let's say your svg image on /../images/svg-from-server.svg is something like

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
  <circle id="background_45_" style="fill:#ECF0F0;" cx="256" cy="256" r="256"></circle>
  <path style="fill:#E27C3E;" d="...."></path>
  <polygon style="fill:#4C738A;" points="..."></polygon>
</svg>

Then once you load your page it would look like:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">

  <head>
    <link rel="shortcut icon" href="/../images/favicon.ico"/>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>e-html</title>
    <link rel="stylesheet" href="/../css/main.css">
    <script src="/../js/ehtml.bundle.min.js" type="text/javascript"></script>
  </head>

  <body class="main">

    <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
      <circle id="background_45_" style="fill:#ECF0F0;" cx="256" cy="256" r="256"></circle>
      <path style="fill:#E27C3E;" d="...."></path>
      <polygon style="fill:#4C738A;" points="..."></polygon>
    </svg>

  </body>

</html>
E-WRAPPER template (v1.0.16)

Template with is="e-wrapper" attribute is very powerful element which you can use for wrapping your dynamic content with some base static template.

So, let's say you have basic static template in your app:

<div class="base">
  <p>
    Header content
  </p>
  <p id="dynamic-content">
    <span>Default content</span>
  </p>
  <p>
    Footer content
  </p>
</div> 

Then you can use this static template as a warapper in other pages

<body class="main">
  <template 
    is="e-wrapper" 
    data-src="/../html/wrapper.html" 
    data-where-to-place="#dynamic-content" 
    data-how-to-place="instead">
    <p>
      Variation of content
    </p>
  </template>
</body>

Attribute data-src specifies a path where base static template is served. By attribute data-where-to-place you specify which element from the template you want to wrap or replace with the content inside of e-wrapper template.

You can aso specify the way how it can be wrapped via data-how-to-place attribute with one of the possible values: 'instead', 'before' and 'after'. If you use option 'instead', element by selector in attribute data-where-to-place will be just replaced with content in your template e-wrapper. By using 'before' option, content in e-wrapper will be placed before the first element with selector in the attribute data-where-to-place. And by using 'after' option, the content will be placed after the element.

So, your page with e-wrapper in this case will be rendered like

<div class="base">
  <p>
    Header content
  </p>
  <p>
    Variation of content
  </p>
  <p>
    Footer content
  </p>
</div> 

You can also use data-headers attribute, if needed.

Supported actions on response

EHTML supports some actions on response that you get in some elements like e-json, e-form or e-google-oauth-button. You can specify these actions in the attribute data-actions-on-response with response, which name you have to specify in the attribute data-response-name.

logToConsole

If you just want to log response to console, use logToConsole function:

data-actions-on-response="logToConsole('${someResponse}')"
mapToTemplate

You can map response object to an element which must be <template>.

data-actions-on-response="mapToTemplate('${someResponse.body}', '#someTemplateId')"

Element with id someTemplateId must have data-object-name, so you can use object name in the mapping. You can use any selector for the second argument, but this function will only map the first element that was found by the selector you specified.

This function works only for attributes of html elements. So if you want to map an object to some text in some element, just use custom attribute data-text. For values of input fields use custom attribute data-value. Other attributes are mapping with their original names without data- prefix.

redirect

You can redirect on response:

data-actions-on-response="redirect('/../some/path/${someResponse.body.itemId}')"
turboRedirect

You can redirect in the turbo style on response:

data-actions-on-response="turboRedirect('/../some/path/${someResponse.body.itemId}', { 'headerName': 'headerValue' }, { 'progressBarPlace': '#boxId', 'progressBarClassName': 'progress-bar', 'ajaxFavicon': '/../images/favicon.gif' })"

You can specify headers if you need them, otherwise just put empty object: { }. Also, you can specify optionaly progressBarPlace, progressBarClassName and ajaxFavicon like in the e-turbolink.

reload

You can reload a page on response:

data-actions-on-response="reload()"
saveToLocalStorage / saveToSessionStorage

You can save some value from response to the localStorage or sessionStorage:

data-actions-on-response="
  saveToLocalStorage('key', ${someResponse.body.value}');
  saveToSessionStorage('key', ${someResponse.body.value}');
"
removeFromLocalStorage / removeFromSessionStorage

You can remove values from the localStorage or sessionStorage on response:

data-actions-on-response="
  removeFromLocalStorage('key');
  removeFromSessionStorage('key');
"
hideElms / showElms / disableElms / enableElms

You can hide, show, disable and enable elements on response:

data-actions-on-response="
  hideElms('#someId', '.someClassName', ...);
  showElms('#someId', '.someClassName', ...);
  disableElms('#someId', '.someClassName', ...);
  enableElms('#someId', '.someClassName', ...);
"
removeElms (v1.0.8)

You can remove elements on response:

data-actions-on-response="
  removeElms('#someId', '.someClassName', ...);
"
toggleElms

You can toggle class name for elments on response:

data-actions-on-response="toggleElms('someClassName', '#someId', '.someClassName', ...)"
innerHTML / addHTMLTo / textContent

You can load html or text content into some element from some resource on response:

data-actions-on-response="
  innerHTML('#someElmSelector', '/../path/to/html/file.html', { 'headerName': 'headerValue' });
  addHTMLTo('#someElmSelector', '/../path/to/html/file.html', { 'headerName': 'headerValue' });
  textContent('#someElmSelector', '/../path/to/html/file.html', { 'headerName': 'headerValue' });
"

These three actions have arguments: elmSelector, url and headers. So, they load or append some content that was fetch by url and headers into the element that you specify by elmSelector.

innerHTMLFromResponse / addHTMLToFromResponse / textContentFromResponse (v1.0.21)

You can load html or text content into some element from the response you've got:

data-actions-on-response="
  innerHTMLFromResponse('#someElmSelector', '${response.body.html}');
  addHTMLToFromResponse('#someElmSelector', '${response.body.html}');
  textContentFromResponse('#someElmSelector', '${response.body.text}');
"

These three actions have arguments: elmSelector, html(text). So, you can get html(text) property from your JSON response and put it into some element with specified selector.

changeValueOf

You can change the value of some input element on response:

data-actions-on-response="changeValueOf('#someElmSelector', '${someResponse.body.someValue}')"
updateAttribute (v1.0.2)

You can update an attribute of some element on response:

data-actions-on-response="updateAttribute('#someElmSelector', 'attrName', 'newAttrValue')"
scrollIntoView (v1.0.20)

You can scroll to element on response:

data-actions-on-response="scrollIntoView('#someElmSelector')"

You can combine several actions on one response:

data-actions-on-response="
  mapToTemplate('${someResponse.body}', '#box');
  showElms('#box');
  logToConsole('statusCode:', '${someResponse.statusCode}');
"

You must use delimiter ; between actions.

Also, you can use simple if statement for each action if you want them to be invoked only in the particular cases:

data-actions-on-response="
  if ('${someResponse.statusCode === 200}') mapToTemplate('${someResponse.body}', '#response-box');
  if ('${someResponse.statusCode !== 200}') mapToTemplate('${someResponse.body}', '#error-box');
"

You can specify only one action for each if statement, and each if statement must be without curly braces.

You can also use actions in event listeners of elements, more details about that you can find in the examples.

Examples

You can find the code in the examples folder.

You can run examples locally:

git clone [email protected]:Guseyn/EHTML.git
cd EHTML
npm i
npm run examples

And then just open http://localhost:8000/.

Simple E-HTML page

demo

e-html

code
<body class="main">
  <div class="base">
    <e-html data-src="/../html/why-i-dont-use-promises-and-async-await.html"></e-html>
    <e-html data-src="/../html/simple-rs-jwt.html"></e-html>
    <e-html data-src="/../html/simple-jwt.html"></e-html>
  </div> 
</body>

link to the source code

Simple E-JSON

demo
IMAGE ALT TEXT HERE
response
Request URL: http://localhost:8000/profile?name=John
Request Method: GET
-----------------------------------------------------
Status Code: 200 ok
Content-Type: application/json
{
  "age": 27,
  "country": "Canada",
  "email": "[email protected]",
  "name": "John",
  "photo": "/../images/John.svg",
  "profession": "dentist",
}
code
<body class="main">
  <div class="base">
    <e-json
      data-src="/../profile?name=John"
      data-response-name="profileResponse"
      data-actions-on-response="mapToTemplate('${profileResponse.body}', '#profile-template')"
      data-ajax-icon="#ajax-icon"
    >
      <div class="profile-box">
        <img class="ajax-icon" id="ajax-icon" src="/../images/red-ajax-loader.gif"/>
        <template id="profile-template" data-object-name="profile">
          <img class="photo" src="${profile.photo}"/>
          <div class="user-info">
            <div class="name" data-text="${profile.name}"></div>
            <div class="email" data-text="${profile.email}"></div>
            <div class="other-details">
              <div data-text="Age: ${profile.age}"></div>
              <div data-text="Country: ${profile.country}"></div>
              <div data-text="Profession: ${profile.profession}"></div>
            </div>
          </div>
        </template>
      </div>
    </e-json>
  </div> 
</body>

link to the source code

E-JSON with progress bar

demo
IMAGE ALT TEXT HERE
response
Request URL: https://guseyn.com/bigjson
Request Method: GET
---------------------------------------
Status Code: 200 ok
Content-Length: 1853154
Content-Type: application/json
code
<body class="main">
  <div class="base">
    <e-json
      data-src="https://guseyn.com/bigjson"
      data-response-name="response"
      data-progress-bar="#progress-bar"
      data-actions-on-response="mapToTemplate('${response}', '#response-template')"
    >
      <div class="response-box">
        <progress id="progress-bar"></progress>
        <template id="response-template" data-object-name="response">
          <div class="response-info">
            <div>
              Big JSON file has been fetched with status: <b data-text="${response.statusCode}"></b>
            </div>
            <div>
              Content-Length is: <b data-text="${response.headers['content-length']} bytes"></b>
            </div>
            <div>
              Name and email of the first user in the response: <br>
              <b data-text="name: ${response.body.items[0].name}, email: ${response.body.items[0].email}"></b>
            </div>
          </div>
        </template>
      </div>
    </e-json>
  </div> 
</body>

link to the source code

E-JSON with mapped error

demo
IMAGE ALT TEXT HERE
response
Request URL: http://localhost:8000/profile?name=Unknown
Request Method: GET
-------------------------------------------------------
Status Code: 404 profile is not found
Content-Type: application/json
{
  "error": "profile is not found"
}
code
<body class="main">
  <div class="base">
    <e-json
      data-src="/../profile?name=Unknown"
      data-response-name="profileResponse"
      data-actions-on-response="mapToTemplate('${profileResponse}', '#profile-template')"
      data-ajax-icon="#ajax-icon"
    >
      <div class="profile-box">
        <img class="ajax-icon" id="ajax-icon" src="/../images/ajax-icon.svg"/>
        <template id="profile-template" data-object-name="profileResponse">
          <template is="e-if" data-condition-to-display="${profileResponse.statusCode === 200}">
            <img class="photo" src="${profileResponse.body.photo}"/>
            <div class="user-info">
              <div class="name" data-text="${profileResponse.body.name}"></div>
              <div class="email" data-text="${profileResponse.body.email}"></div>
              <div class="other-details">
                <div data-text="Age: ${profileResponse.body.age}"></div>
                <div data-text="Country: ${profileResponse.body.country}"></div>
                <div data-text="Profession: ${profileResponse.body.profession}"></div>
              </div>
            </div>
          </template>
          <template is="e-if" data-condition-to-display="${profileResponse.statusCode === 404}">
            <div class="error-box">
              User Not Found
            </div>
          </template>
        </template>
      </div>
    </e-json>
  </div> 
</body>

link to the source code

E-JSON as a template

demo
IMAGE ALT TEXT HERE
response
Request URL: http://localhost:8000/profile?name=Amanda
Request Method: GET
-----------------------------------------------------
Status Code: 200 ok
Content-Type: application/json
{
  "photo": "/../images/Amanda.svg",
  "name": "Amanda",
  "email": "[email protected]",
  "age": 24,
  "country": "Australia",
  "profession": "race driver"
}
code
<body class="main">
  <div class="base">
    <div class="profile-box">
      <img class="ajax-icon" id="ajax-icon" src="/../images/ajax-icon.svg"/>
      <template
        is="e-json"
        data-src="/../profile?name=Amanda"
        data-ajax-icon="#ajax-icon"
        data-object-name="profileResponse"
      >
        <img class="photo" src="${profileResponse.body.photo}"/>
        <div class="user-info">
          <div class="name" data-text="${profileResponse.body.name}"></div>
          <div class="email" data-text="${profileResponse.body.email}"></div>
          <div class="other-details">
            <div data-text="Age: ${profileResponse.body.age}"></div>
            <div data-text="Country: ${profileResponse.body.country}"></div>
            <div data-text="Profession: ${profileResponse.body.profession}"></div>
          </div>
        </div>
      </template>
    </div>
  </div> 
</body>

link to the source code

Simple E-FOR-EACH

demo
IMAGE ALT TEXT HERE
response
Request URL: http://localhost:8000/playlist
Request Method: GET
-------------------------------------------
Status Code: 200 ok
Content-Type: application/json
{
  "title": "My playlist ♥",
  "photo":"/../images/guitar.svg",
  "songs":[
    { "title":"Nantes", "artist": "Beirut", "album": "The Flying Club Cup", "link": "https://genius.com/Beirut-nantes-lyrics" },
    { "title": "My Kind Of Woman", "artist": "Mac DeMarco", "album": "2", "link": "https://genius.com/Mac-demarco-my-kind-of-woman-lyrics" },
    { "title": "Black Treacle", "artist": "Arctic Monkeys", "album": "Suck It And See", "link": "https://genius.com/Arctic-monkeys-black-treacle-lyrics" },
    { "title": "Swing Low", "artist": "The Kooks","album":"Let's Go Sunshine", "link":"https://genius.com/The-kooks-swing-low-lyrics" },
    { "title": "Seen It All", "artist": "Jake Bugg", "album": "Jake Bugg", "link":"https://genius.com/Jake-bugg-seen-it-all-lyrics" }
  ]
}
code
<body class="main">
  <div class="base">
    <e-json
      data-src="/../playlist"
      data-response-name="response"
      data-actions-on-response="mapToTemplate('${response.body}', '#response-template')"
      data-ajax-icon="#ajax-icon"
    >
      <div class="response-box">
        <img class="ajax-icon" id="ajax-icon" src="/../images/ajax-icon.svg"/>
        <template id="response-template" data-object-name="playlist">
          <img class="photo" src="${playlist.photo}"/>
          <div class="playlist-info">
            <div class="song-title" data-text="${playlist.title}"></div>
            <div class="songs-box">
              <template is="e-for-each" data-list-to-iterate="${playlist.songs}" data-item-name="song">
                <div class="song-box">
                  <div><b>Title: </b><span data-text="${song.title}"></span></div>
                  <div><b>Artist: </b><span data-text="${song.artist}"></span></div>
                  <div><b>Album: </b><span data-text="${song.album}"></span></div>
                  <div><a href="${song.link}">More info</a><b></b></div>
                </div>
              </template>
            </div>
          </div>
        </template>
      </div>
    </e-json>
  </div> 
</body>

link to the source code

Simple E-IF

demo
IMAGE ALT TEXT HERE
response
Request URL: http://localhost:8000/playlist
Request Method: GET
-------------------------------------------
Status Code: 200 ok
Content-Type: application/json
{
  "title": "My playlist ♥",
  "photo":"/../images/guitar.svg",
  "songs":[
    { "title":"Nantes", "artist": "Beirut", "album": "The Flying Club Cup", "link": "https://genius.com/Beirut-nantes-lyrics" },
    { "title": "My Kind Of Woman", "artist": "Mac DeMarco", "album": "2", "link": "https://genius.com/Mac-demarco-my-kind-of-woman-lyrics" },
    { "title": "Black Treacle", "artist": "Arctic Monkeys", "album": "Suck It And See", "link": "https://genius.com/Arctic-monkeys-black-treacle-lyrics" },
    { "title": "Swing Low", "artist": "The Kooks","album":"Let's Go Sunshine", "link":"https://genius.com/The-kooks-swing-low-lyrics" },
    { "title": "Seen It All", "artist": "Jake Bugg", "album": "Jake Bugg", "link":"https://genius.com/Jake-bugg-seen-it-all-lyrics" }
  ]
}
code
<body class="main">
  <div class="base">
    <e-json
      data-src="/../playlist"
      data-response-name="response"
      data-actions-on-response="mapToTemplate('${response.body}', '#response-template')"
      data-ajax-icon="#ajax-icon"
    >
      <div class="response-box">
        <img class="ajax-icon" id="ajax-icon" src="/../images/ajax-icon.svg"/>
        <template id="response-template" data-object-name="playlist">
          <img class="photo" src="${playlist.photo}"/>
          <div class="playlist-info">
            <div class="playlist-title" data-text="${playlist.title}">
              <div>only from self-titled albums</div>
            </div>
            <div class="songs-box">
              <template is="e-for-each" data-list-to-iterate="${playlist.songs}" data-item-name="song">
                <template is="e-if" data-condition-to-display="${song.artist === song.album}">
                  <div class="song-box">
                    <div><b>Title: </b><span data-text="${song.title}"></span></div>
                    <div><b>Artist: </b><span data-text="${song.artist}"></span></div>
                    <div><b>Album: </b><span data-text="${song.album}"></span></div>
                    <div><a href="${song.link}">More info</a><b></b></div>
                  </div>
                </template>
              </template>
            </div>
          </div>
        </template>
      </div>
    </e-json>
  </div> 
</body>

link to the source code

Simple E-FORM

demo
IMAGE ALT TEXT HERE
response
Request URL: https://guseyn.com/echo
Request Method: POST
Request Body: {"name":"Guseyn Ismayylov","email":"[email protected]","github":"https://github.com/Guseyn","langs":["php","js"],"resume":[{"name":"resume.pdf","size":151153,"type":"application/pdf","content":"data:application/pdf;base64,JVBERi0x...}]}
-------------------------------------------
Status Code: 200 ok
Content-Type: application/json
{
  "name": "Guseyn Ismayylov",
  "email": "[email protected]",
  "github": "https://github.com/Guseyn",
  "langs": [ "php", "js"],
  "resume": [ 
    {
      "name":"resume.pdf",
      "size":151153,
      "type":"application/pdf",
      "content":"data:application/pdf;base64,JVBERi0x.."
    }
  ]
}
code
<body class="main">
  <div class="base">
    <e-form
      class="form"
      id="form"
      data-validation-error-message="Enter correct data into the form, please"
      data-validation-error-class-for-message-box="form-message-error">

      <div id="form-content">
        <div class="name">
          Simple Job Application Form
        </div>
        <div class="form-label">Your Name:</div>
        <input
          type="text"
          name="name"
          class="form-input"
          required
          data-validation-pattern="^[a-z ,.'-]+$"
          data-validation-bad-format-error-message="Name can contain only alphabetic characters"
          data-validation-absence-error-message="Name is required"
          data-validation-error-class-for-element="elm-error"
          data-validation-error-class-for-message-box="message-error">
        
        <div class="form-label">Your Email:</div>
        <input
          type="email"
          name="email"
          class="form-input"
          required
          data-validation-pattern="email"
          data-validation-bad-format-error-message="This is not proper email address"
          data-validation-absence-error-message="Email is required"
          data-validation-error-class-for-element="elm-error"
          data-validation-error-class-for-message-box="message-error">  
        <div class="form-label">Your GitHub:</div>
        <input
          type="url"
          name="github"
          class="form-input"
          required
          pattern="url"
          data-validation-absence-error-message="GitHub is required"
          data-validation-error-class-for-element="elm-error"
          data-validation-error-class-for-message-box="message-error">

        <div class="form-label">Choose languages you know:</div>
        <span class="lang-option">PHP</span>
        <input
          type="checkbox"
          name="langs"
          value="php">
        <span class="lang-option">JS</span>
        <input
          type="checkbox"
          name="langs"
          value="js">
        <span class="lang-option">Ruby</span>
        <input
          type="checkbox"
          name="langs"
          value="ruby">
        <span class="lang-option">Python</span>
        <input
          type="checkbox"
          name="langs"
          value="python">
        <span class="lang-option">C++</span>
        <input
          type="checkbox"
          name="langs"
          value="c++">

        <div class="form-label">Your Resume:</div>
        <input
          type="file"
          name="resume"
          class="form-input"
          data-read-progress-bar="#read-progress-bar"
          multiple required
          data-validation-absence-error-message="Resume is required"
          data-validation-min-files-number="1"
          data-validation-error-class-for-element="elm-error"
          data-validation-error-class-for-message-box="message-error">
        <progress id="read-progress-bar"></progress>

        <button
          data-request-url="https://guseyn.com/echo"
          data-request-method="POST"
          data-request-headers="{}"
          data-upload-progress-bar="#upload-progress-bar"
          data-progress-bar="#progress-bar"
          data-ajax-icon="#ajax-icon"
          data-response-name="response"
          onclick="this.form.submit(this)"
          data-actions-on-response="
            hideElms('#form-content');
            showElms('.applying-response-box');
            mapToTemplate('${response}', '#response-template');
          ">
          Apply
        </button>

        <img id="ajax-icon" class="ajax-icon" src="/../images/ajax-icon.svg"/>
        <progress id="upload-progress-bar"></progress>
        <progress id="progress-bar"></progress>
      </div>

      <div class="applying-response-box" style="display: none;">
        <template id="response-template" data-object-name="response">
          <div class="response-info">
            <div data-text="Thank you for your application, ${response.body.name}!"></div>
          </div>
        </template>
      </div>

    </e-form>
  </div>
</body>
.elm-error {
  border: 1px solid red;
}

.message-error {
  color: red;
}

.form-message-error {
  text-align: center;
  color: red;
  font-family: sans-serif;
}

link to the source code

validation patterns
You can specify in the attribute `data-validation-pattern` following predefined patterns: `date`, `dateTime`, `email`, `month`, `number`, `password`, `tel`, `time`, `url` which have following formats:

```js
const VALIDATION_PATTERNS = {
  date: /[0-3]\d\/[0-1]\d\/\d\d\d\d/,
  dateTime: /[0-3]\d\/[0-1]\d\/\d\d\d\d, \d\d:\d\d/,
  email: /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
  month: /^\d\d\d\d-\d\d$/,
  number: /(\d)+/,
  password: /^.*(?=.{8,})(?=.*[a-zA-Z])(?=.*\d)(?=.*[!#$%&? "]).*$/,
  tel: /[0-9]{0,14}$/,
  time: /\d\d:\d\d/,
  url: /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/
}
```

Or you can specify a string, which would be a base for RegExp with flags `ig`.

E-REUSABLE template with E-FORM

demo
IMAGE ALT TEXT HERE
response
Request URL: https://guseyn.com/echo
Request Method: GET
Request Body: {"name": "some name"}
-------------------------------------------
Status Code: 200 ok
Content-Type: application/json
{
  "name": "some name"
}
code
<body class="main">
  <div class="base">
    <e-form
      class="form"
      id="form"
      data-validation-error-message="Enter correct data into the form, please"
      data-validation-error-class-for-message-box="form-message-error">

      <div id="form-content">
        <div class="form-label">Item name:</div>
        <input
          type="text"
          name="name"
          class="form-input"
          required
          data-validation-pattern="^[a-z ,.'-]+$"
          data-validation-bad-format-error-message="Item name can contain only alphabetic characters"
          data-validation-absence-error-message="Item name is required"
          data-validation-error-class-for-element="elm-error"
          data-validation-error-class-for-message-box="message-error">

        <button
          data-request-url="https://guseyn.com/echo"
          data-request-method="POST"
          data-ajax-icon="#ajax-icon"
          data-response-name="response"
          onclick="this.form.submit(this)"
          data-actions-on-response="
            mapToTemplate('${response}', '#response-template');
          ">
          Add Item
        </button>

        <img id="ajax-icon" class="ajax-icon" src="/../images/ajax-icon.svg"/>
      </div>

      <div class="applying-response-box">
        <div class="name">
          Items:
        </div>
        <div class="response-info">
          <span>item with name: <b>default</b></span>
        </div>
        <template id="response-template" is="e-reusable" data-object-name="response">
          <div class="response-info">
            <span>item with name <b data-text="${response.body.name}"></b></span>
          </div>
        </template>
      </div>

    </e-form>
  </div> 
</body>

link to the source code

Simple E-GOOGLE-OAUTH-BUTTON

demo
IMAGE ALT TEXT HERE
response
Request URL: /../google
Request Method: GET
Request Body: {"googleToken": "<some fetched google token>"}
-------------------------------------------
Status Code: 200 ok
Content-Type: application/json
{
  "jwt": "<some jwt token from your endpoint>"
}
code
<body class="main">
  <div class="base">
    
    <template is="e-if" data-condition-to-display="${localStorage.getItem('jwt') != null}">
      <div class="response-box">
        <div class="response-info">
          <b>Welcome!</b>
        </div>
      </div>
    </template>

    <template is="e-if" data-condition-to-display="${localStorage.getItem('jwt') == null}">
      <div class="login-form">
        <input id="email" type="text" name="email" placeholder="My email" class="login-input">
        <input id="password" type="password" name="password" placeholder="My password" class="login-input">
        <div id="error" class="error"></div>
        <input id="go-button" type="button" value="Sign in" class="login-input">
        <div class="mode">
          <span id="sign-up" class="as-link">Sign up</span>
          /
          <span id="sign-in" class="as-link">Sign in</span>
        </div>
      </div>

      <div style="text-align: center; font-family: sans-serif;">or</div>

      <e-google-oauth-button
        class="customSignIn"
        data-client-id="8310979471-lvmkisk1b33fjd25pjjqe8v8fa72rq2q.apps.googleusercontent.com"
        data-redirect-url="/../google"
        data-cookiepolicy="single_host_origin"
        data-scope="profile"
        data-request-token-key="googleToken"
        data-response-name="responseWithToken"
        data-actions-on-response="
          saveToLocalStorage('jwt', '${responseWithToken.body.jwt}');
          reload();
        "
      >
        <span id="google-icon" class="icon"></span>
        <span class="buttonText">Sign in with Google</span>
      </e-google-oauth-button>
    </template>
  </div>
</body>
.customSignIn {
    margin: 10px auto;
    background: white;
    color: #444;
    width: 200px;
    border-radius: 5px;
    border: thin solid #888;
    box-shadow: 1px 1px 1px grey;
    white-space: nowrap;
    display: block;
}

.customSignIn:hover {
  cursor: pointer;
}

#google-icon {
  background: url('/../images/g-logo.png') transparent 5px 50% no-repeat;
}

span.icon {
  display: inline-block;
  vertical-align: middle;
  width: 48px;
  height: 48px;
}

span.buttonText {
  display: inline-block;
  vertical-align: middle;
  font-size: 14px;
  font-weight: bold;
  margin-left: 5px;
  font-family: 'Roboto', sans-serif;
}

link to the source code

E-PAGE-WITH-URL

demo
IMAGE ALT TEXT HERE
code
<body class="main">
  <template is="e-page-with-url" data-url-pattern="/e-page-url.html/{one}/{two}/{three}?{query}">
    <input data-value="${urlParams.one}"/>
    <input data-value="${urlParams.two}"/>
    <input data-value="${urlParams.three}"/>
    <input data-value="${urlParams.query}"/>
  </template>
</body>

link to the source code

E-PAGE-WITH-URL + E-JSON

demo
IMAGE ALT TEXT HERE
code
<body class="main">
  <template is="e-page-with-url" data-url-pattern="/e-page-url-with-e-json.html?{name}">
    <div class="base">
      <e-json
        data-src="/../profile?name=${urlParams.name}"
        data-response-name="profileResponse"
        data-actions-on-response="mapToTemplate('${profileResponse}', '#profile-template')"
        data-ajax-icon="#ajax-icon"
      >
        <div class="profile-box">
          <img class="ajax-icon" id="ajax-icon" src="/../images/ajax-icon.svg"/>
          <template id="profile-template" data-object-name="profileResponse">
            <template is="e-if" data-condition-to-display="${profileResponse.statusCode === 200}">
              <img class="photo" src="${profileResponse.body.photo}"/>
              <div class="user-info">
                <div class="name" data-text="${profileResponse.body.name}"></div>
                <div class="email" data-text="${profileResponse.body.email}"></div>
                <div class="other-details">
                  <div data-text="Age: ${profileResponse.body.age}"></div>
                  <div data-text="Country: ${profileResponse.body.country}"></div>
                  <div data-text="Profession: ${profileResponse.body.profession}"></div>
                </div>
              </div>
            </template>
            <template is="e-if" data-condition-to-display="${profileResponse.statusCode === 404}">
              <div class="error-box">
                User Not Found
              </div>
            </template>
          </template>
        </div>
      </e-json>
    </div> 
  </template>
</body>

link to the source code

E-TURBOLINK

demo
IMAGE ALT TEXT HERE
code
<body>
  <div style="margin-left: 20px; margin-top: 20px;">
    <e-turbolink data-href="/../html/big.html" data-with-progress-bar="progress-bar">GO TO NICE PIC</e-turbolink>
  </div>
</body>

link to the source code

E-PAGE-WITH-URL + E-SELECT (with turbo-redirect)

demo
IMAGE ALT TEXT HERE
code
<body class="main">
  <template is="e-page-with-url" data-url-pattern="/turbo-actions.html?{color}">
    <div class="base">
      <e-select
        class="big-select"
        name="color" 
        value="${urlParams.color}"
        onchange="
          window.turboRedirect(this, (target) => {
            return '/../e-page-with-url-and-e-select-with-turbo-redirect.html?color=' + target.value
          })
        "
      >
        <option value="red" name="color">Red</option>
        <option value="green" name="color">Green</option>
        <option value="blue" name="color">Blue</option>
      </e-select>
      <div id="color" width="100px;">
        <div class="circle" style="background: ${urlParams.color};"></div>
      </div>
    </div>
  </template>
</body>

link to the source code

Simple E-GITHUB-OAUTH-BUTTON

demo
IMAGE ALT TEXT HERE
response
# request is made on redirect uri page
Request URL: /../github
Request Method: GET
Request Body: {"code": "<some retrieved code from redirect uri page>"}
-------------------------------------------
Status Code: 200 ok
Content-Type: application/json
{
  "jwt": "<some jwt token from your endpoint>"
}
code
<body class="main">
  <div class="base">
    
    <template is="e-if" data-condition-to-display="${localStorage.getItem('jwt') != null}">
      <div class="response-box">
        <div class="response-info">
          <b>Welcome!</b>
        </div>
      </div>
    </template>

    <template is="e-if" data-condition-to-display="${localStorage.getItem('jwt') == null}">
      <div class="login-form">
        <input id="email" type="text" name="email" placeholder="My email" class="login-input">
        <input id="password" type="password" name="password" placeholder="My password" class="login-input">
        <div id="error" class="error"></div>
        <input id="go-button" type="button" value="Sign in" class="login-input">
        <div class="mode">
          <span id="sign-up" class="as-link">Sign up</span>
          /
          <span id="sign-in" class="as-link">Sign in</span>
        </div>
      </div>

      <div style="text-align: center; font-family: sans-serif;">or</div>

      <e-github-oauth-button
        class="customSignIn"
        data-client-id="9740bb12713949b1c23d"
        data-redirect-uri="http://localhost:8000/html/github.html/"
        data-scope="user,repo">
        <span id="github-icon" class="icon"></span>
        <span class="buttonText">Sign in with Github</span>
      </e-github-oauth-button>
    </template>
  </div>
</body>
.customSignIn {
    margin: 10px auto;
    background: white;
    color: #444;
    width: 200px;
    border-radius: 5px;
    border: thin solid #888;
    box-shadow: 1px 1px 1px grey;
    white-space: nowrap;
    display: block;
}

.customSignIn:hover {
  cursor: pointer;
}

#github-icon {
  background: url('/../images/github-logo.png') transparent 5px 50% no-repeat;
}

span.icon {
  display: inline-block;
  vertical-align: middle;
  width: 48px;
  height: 48px;
}

span.buttonText {
  display: inline-block;
  vertical-align: middle;
  font-size: 14px;
  font-weight: bold;
  margin-left: 5px;
  font-family: 'Roboto', sans-serif;
}

Page on redirect uri:

<body class="main">
  <template is="e-page-with-url" data-url-pattern="/html/github.html?{code}">
    <div class="base">
      <e-form
        data-request-url="/../github"
        data-request-method="POST"
        data-request-headers="{}"
        data-ajax-icon="#ajax-icon"
        data-response-name="responseWithToken"
        data-actions-on-response="
          saveToLocalStorage('jwt', '${responseWithToken.body.jwt}');
          turboRedirect('/../e-github-oauth-button.html');
      ">
        <input type="hidden" name="code" value="${urlParams.code}">
        <img id="ajax-icon" class="ajax-icon" src="/../images/ajax-icon.svg"/>
      </e-form>
    </div> 
  </template>
</body>

link to the source code

Contribution and QA

If you have any questions or concers about EHTML, please feel free to share them in the issues. If you want to send a patch, feel free to create a fork and send it via pull request.

Comments
  • Bump browserslist from 4.6.6 to 4.20.4

    Bump browserslist from 4.6.6 to 4.20.4

    Bumps browserslist from 4.6.6 to 4.20.4.

    Changelog

    Sourced from browserslist's changelog.

    4.20.4

    • Fix Opera in mobileToDesktop (by Pig Fang).

    4.20.3

    • Add Baidu to dead browsers (by Igor Lukanin).

    4.20.2

    • Fixed package.funding URL format.

    4.20.1

    • Fixed package.funding.
    • Fixed docs (by Michael Lohmann).

    4.20

    • Added last 2 node versions and last 2 node major versions (by @​g-plane).

    4.19.3

    • Updated Firefox ESR (by Christophe Coevoet).

    4.19.2

    • Fixed --help output.

    4.19.1

    • Fixed throwOnMissing types (by Øyvind Saltvik).

    4.19

    • Added queries grammar definition (by Pig Fang).
    • Added throwOnMissing option (by Øyvind Saltvik).
    • Fixed null data ignoring in < 50% in CN (byPig Fang).
    • Fixed data parsing in in my stats (by Sun Xiaoran).
    • Fixed yarn.lock support with integrity (by Alexey Berezin).
    • Fixed Yarn Berry error message in --update-db.

    4.18.1

    • Fixed case inventiveness for cover queries (by Pig Fang).
    • Fixed since 1970 query for null in release date (by Pig Fang).

    4.18

    • Added --ignore-unknown-versions CLI option (by Pig Fang).

    4.17.6

    • Fixed sharable config resolution (by Adaline Valentina Simonian).

    4.17.5

    • Fixed --update-db for some pnpm cases.

    4.17.4

    • Reduced package size.

    4.17.3

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump tar from 4.4.8 to 4.4.19

    Bump tar from 4.4.8 to 4.4.19

    Bumps tar from 4.4.8 to 4.4.19.

    Commits
    • 9a6faa0 4.4.19
    • 70ef812 drop dirCache for symlink on all platforms
    • 3e35515 4.4.18
    • 52b09e3 fix: prevent path escape using drive-relative paths
    • bb93ba2 fix: reserve paths properly for unicode, windows
    • 2f1bca0 fix: prune dirCache properly for unicode, windows
    • 9bf70a8 4.4.17
    • 6aafff0 fix: skip extract if linkpath is stripped entirely
    • 5c5059a fix: reserve paths case-insensitively
    • fd6accb 4.4.16
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump grunt from 1.0.4 to 1.5.3

    Bump grunt from 1.0.4 to 1.5.3

    Bumps grunt from 1.0.4 to 1.5.3.

    Release notes

    Sourced from grunt's releases.

    v1.5.3

    • Merge pull request #1745 from gruntjs/fix-copy-op 572d79b
    • Patch up race condition in symlink copying. 58016ff
    • Merge pull request #1746 from JamieSlome/patch-1 0749e1d
    • Create SECURITY.md 69b7c50

    https://github.com/gruntjs/grunt/compare/v1.5.2...v1.5.3

    v1.5.2

    • Update Changelog 7f15fd5
    • Merge pull request #1743 from gruntjs/cleanup-link b0ec6e1
    • Clean up link handling 433f91b

    https://github.com/gruntjs/grunt/compare/v1.5.1...v1.5.2

    v1.5.1

    • Merge pull request #1742 from gruntjs/update-symlink-test ad22608
    • Fix symlink test 0652305

    https://github.com/gruntjs/grunt/compare/v1.5.0...v1.5.1

    v1.5.0

    • Updated changelog b2b2c2b
    • Merge pull request #1740 from gruntjs/update-deps-22-10 3eda6ae
    • Update testing matrix 47d32de
    • More updates 2e9161c
    • Remove console log 04b960e
    • Update dependencies, tests... aad3d45
    • Merge pull request #1736 from justlep/main fdc7056
    • support .cjs extension e35fe54

    https://github.com/gruntjs/grunt/compare/v1.4.1...v1.5.0

    v1.4.1

    • Update Changelog e7625e5
    • Merge pull request #1731 from gruntjs/update-options 5d67e34
    • Fix ci install d13bf88
    • Switch to Actions 08896ae
    • Update grunt-known-options eee0673
    • Add note about a breaking change 1b6e288

    https://github.com/gruntjs/grunt/compare/v1.4.0...v1.4.1

    v1.4.0

    • Merge pull request #1728 from gruntjs/update-deps-changelog 63b2e89
    • Update changelog and util dep 106ed17
    • Merge pull request #1727 from gruntjs/update-deps-apr 49de70b
    • Update CLI and nodeunit 47cf8b6
    • Merge pull request #1722 from gruntjs/update-through e86db1c
    • Update deps 4952368

    ... (truncated)

    Changelog

    Sourced from grunt's changelog.

    v1.5.3 date: 2022-04-23 changes: - Patch up race condition in symlink copying. v1.5.2 date: 2022-04-12 changes: - Unlink symlinks when copy destination is a symlink. v1.5.1 date: 2022-04-11 changes: - Fixed symlink destination handling. v1.5.0 date: 2022-04-10 changes: - Updated dependencies. - Add symlink handling for copying files. v1.4.1 date: 2021-05-24 changes: - Fix --preload option to be a known option - Switch to GitHub Actions v1.4.0 date: 2021-04-21 changes: - Security fixes in production and dev dependencies - Liftup/Liftoff upgrade breaking change. Update your scripts to use --preload instead of --require. Ref: https://github.com/js-cli/js-liftoff/commit/e7a969d6706e730d90abb4e24d3cb4d3bce06ddb. v1.3.0 date: 2020-08-18 changes: - Switch to use safeLoad for loading YML files via file.readYAML. - Upgrade legacy-log to ~3.0.0. - Upgrade legacy-util to ~2.0.0. v1.2.1 date: 2020-07-07 changes: - Remove path-is-absolute dependency. (PR: gruntjs/grunt#1715) v1.2.0 date: 2020-07-03 changes: - Allow usage of grunt plugins that are located in any location that is visible to Node.js and NPM, instead of node_modules directly inside package that have a dev dependency to these plugins. (PR: gruntjs/grunt#1677) - Removed coffeescript from dependencies. To ease transition, if coffeescript is still around, Grunt will attempt to load it. If it is not, and the user loads a CoffeeScript file, Grunt will print a useful error indicating that the coffeescript package should be installed as a dev dependency.

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump grunt from 1.0.4 to 1.5.2

    Bump grunt from 1.0.4 to 1.5.2

    Bumps grunt from 1.0.4 to 1.5.2.

    Release notes

    Sourced from grunt's releases.

    v1.5.2

    • Update Changelog 7f15fd5
    • Merge pull request #1743 from gruntjs/cleanup-link b0ec6e1
    • Clean up link handling 433f91b

    https://github.com/gruntjs/grunt/compare/v1.5.1...v1.5.2

    v1.5.1

    • Merge pull request #1742 from gruntjs/update-symlink-test ad22608
    • Fix symlink test 0652305

    https://github.com/gruntjs/grunt/compare/v1.5.0...v1.5.1

    v1.5.0

    • Updated changelog b2b2c2b
    • Merge pull request #1740 from gruntjs/update-deps-22-10 3eda6ae
    • Update testing matrix 47d32de
    • More updates 2e9161c
    • Remove console log 04b960e
    • Update dependencies, tests... aad3d45
    • Merge pull request #1736 from justlep/main fdc7056
    • support .cjs extension e35fe54

    https://github.com/gruntjs/grunt/compare/v1.4.1...v1.5.0

    v1.4.1

    • Update Changelog e7625e5
    • Merge pull request #1731 from gruntjs/update-options 5d67e34
    • Fix ci install d13bf88
    • Switch to Actions 08896ae
    • Update grunt-known-options eee0673
    • Add note about a breaking change 1b6e288

    https://github.com/gruntjs/grunt/compare/v1.4.0...v1.4.1

    v1.4.0

    • Merge pull request #1728 from gruntjs/update-deps-changelog 63b2e89
    • Update changelog and util dep 106ed17
    • Merge pull request #1727 from gruntjs/update-deps-apr 49de70b
    • Update CLI and nodeunit 47cf8b6
    • Merge pull request #1722 from gruntjs/update-through e86db1c
    • Update deps 4952368

    https://github.com/gruntjs/grunt/compare/v1.3.0...v1.4.0

    v1.3.0

    • Merge pull request #1720 from gruntjs/update-changelog-deps faab6be
    • Update Changelog and legacy-util dependency 520fedb
    • Merge pull request #1719 from gruntjs/yaml-refactor 7e669ac
    • Switch to use safeLoad for loading YML files via file.readYAML. e350cea

    ... (truncated)

    Changelog

    Sourced from grunt's changelog.

    v1.5.2 date: 2022-04-12 changes: - Unlink symlinks when copy destination is a symlink. v1.5.1 date: 2022-04-11 changes: - Fixed symlink destination handling. v1.5.0 date: 2022-04-10 changes: - Updated dependencies. - Add symlink handling for copying files. v1.4.1 date: 2021-05-24 changes: - Fix --preload option to be a known option - Switch to GitHub Actions v1.4.0 date: 2021-04-21 changes: - Security fixes in production and dev dependencies - Liftup/Liftoff upgrade breaking change. Update your scripts to use --preload instead of --require. Ref: https://github.com/js-cli/js-liftoff/commit/e7a969d6706e730d90abb4e24d3cb4d3bce06ddb. v1.3.0 date: 2020-08-18 changes: - Switch to use safeLoad for loading YML files via file.readYAML. - Upgrade legacy-log to ~3.0.0. - Upgrade legacy-util to ~2.0.0. v1.2.1 date: 2020-07-07 changes: - Remove path-is-absolute dependency. (PR: gruntjs/grunt#1715) v1.2.0 date: 2020-07-03 changes: - Allow usage of grunt plugins that are located in any location that is visible to Node.js and NPM, instead of node_modules directly inside package that have a dev dependency to these plugins. (PR: gruntjs/grunt#1677) - Removed coffeescript from dependencies. To ease transition, if coffeescript is still around, Grunt will attempt to load it. If it is not, and the user loads a CoffeeScript file, Grunt will print a useful error indicating that the coffeescript package should be installed as a dev dependency. This is considerably more user-friendly than dropping the require entirely, but doing so is feasible with the latest grunt-cli as users may simply use grunt --require coffeescript/register. (PR: gruntjs/grunt#1675)

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump ajv from 6.10.2 to 6.12.6

    Bump ajv from 6.10.2 to 6.12.6

    Bumps ajv from 6.10.2 to 6.12.6.

    Release notes

    Sourced from ajv's releases.

    v6.12.6

    Fix performance issue of "url" format.

    v6.12.5

    Fix uri scheme validation (@​ChALkeR). Fix boolean schemas with strictKeywords option (#1270)

    v6.12.4

    Fix: coercion of one-item arrays to scalar that should fail validation (failing example).

    v6.12.3

    Pass schema object to processCode function Option for strictNumbers (@​issacgerges, #1128) Fixed vulnerability related to untrusted schemas (CVE-2020-15366)

    v6.12.2

    Removed post-install script

    v6.12.1

    Docs and dependency updates

    v6.12.0

    Improved hostname validation (@​sambauers, #1143) Option keywords to add custom keywords (@​franciscomorais, #1137) Types fixes (@​boenrobot, @​MattiAstedrone) Docs:

    v6.11.0

    Time formats support two digit and colon-less variants of timezone offset (#1061 , @​cjpillsbury) Docs: RegExp related security considerations Tests: Disabled failing typescript test

    Commits
    • fe59143 6.12.6
    • d580d3e Merge pull request #1298 from ajv-validator/fix-url
    • fd36389 fix: regular expression for "url" format
    • 490e34c docs: link to v7-beta branch
    • 9cd93a1 docs: note about v7 in readme
    • 877d286 Merge pull request #1262 from b4h0-c4t/refactor-opt-object-type
    • f1c8e45 6.12.5
    • 764035e Merge branch 'ChALkeR-chalker/fix-comma'
    • 3798160 Merge branch 'chalker/fix-comma' of git://github.com/ChALkeR/ajv into ChALkeR...
    • a3c7eba Merge branch 'refactor-opt-object-type' of github.com:b4h0-c4t/ajv into refac...
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump cached-path-relative from 1.0.2 to 1.1.0

    Bump cached-path-relative from 1.0.2 to 1.1.0

    Bumps cached-path-relative from 1.0.2 to 1.1.0.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump browserslist from 4.6.6 to 4.16.6

    Bump browserslist from 4.6.6 to 4.16.6

    Bumps browserslist from 4.6.6 to 4.16.6.

    Changelog

    Sourced from browserslist's changelog.

    4.16.6

    • Fixed npm-shrinkwrap.json support in --update-db (by Geoff Newman).

    4.16.5

    • Fixed unsafe RegExp (by Yeting Li).

    4.16.4

    • Fixed unsafe RegExp.
    • Added artifactory support to --update-db (by Ittai Baratz).

    4.16.3

    • Fixed --update-db.

    4.16.2

    4.16.1

    • Fixed Chrome 4 with mobileToDesktop (by Aron Woost).

    4.16

    • Add browserslist config query.

    4.15

    • Add TypeScript types (by Dmitry Semigradsky).

    4.14.7

    • Fixed Yarn Workspaces support to --update-db (by Fausto Núñez Alberro).
    • Added browser changes to --update-db (by @​AleksandrSl).
    • Added color output to --update-db.
    • Updated package.funding to have link to our Open Collective.

    4.14.6

    • Fixed Yarn support in --update-db (by Ivan Storck).
    • Fixed npm 7 support in --update-db.

    4.14.5

    • Fixed last 2 electron versions query (by Sergey Melyukov).

    4.14.4

    • Fixed Unknown version 59 of op_mob error.

    4.14.3

    • Update Firefox ESR.

    4.14.2

    • Fixed --update-db on Windows (by James Ross).
    • Improved --update-db output.

    4.14.1

    • Added --update-db explanation (by Justin Zelinsky).

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump grunt from 1.0.4 to 1.3.0

    Bump grunt from 1.0.4 to 1.3.0

    Bumps grunt from 1.0.4 to 1.3.0.

    Release notes

    Sourced from grunt's releases.

    v1.3.0

    • Merge pull request #1720 from gruntjs/update-changelog-deps faab6be
    • Update Changelog and legacy-util dependency 520fedb
    • Merge pull request #1719 from gruntjs/yaml-refactor 7e669ac
    • Switch to use safeLoad for loading YML files via file.readYAML. e350cea
    • Merge pull request #1718 from gruntjs/legacy-log-bumo 7125f49
    • Bump legacy-log 00d5907

    https://github.com/gruntjs/grunt/compare/v1.2.1...v1.3.0

    v1.2.1

    • Changelog update ae11839
    • Merge pull request #1715 from sibiraj-s/remove-path-is-absolute 9d23cb6
    • Remove path-is-absolute dependency e789b1f

    https://github.com/gruntjs/grunt/compare/v1.2.0...v1.2.1

    v1.2.0

    • Allow usage of grunt plugins that are located in any location that is visible to Node.js and NPM, instead of node_modules directly inside package that have a dev dependency to these plugins. (PR: gruntjs/grunt#1677)
    • Removed coffeescript from dependencies. To ease transition, if coffeescript is still around, Grunt will attempt to load it. If it is not, and the user loads a CoffeeScript file, Grunt will print a useful error indicating that the coffeescript package should be installed as a dev dependency. This is considerably more user-friendly than dropping the require entirely, but doing so is feasible with the latest grunt-cli as users may simply use grunt --require coffeescript/register. (PR: gruntjs/grunt#1675)
    • Exposes Grunt Option keys for ease of use. (PR: gruntjs/grunt#1570)
    • Avoiding infinite loop on very long command names. (PR: gruntjs/grunt#1697)

    v1.1.0

    • Update to mkdirp ~1.0.3
    • Only support versions of Node >= 8
    Changelog

    Sourced from grunt's changelog.

    v1.3.0 date: 2020-08-18 changes: - Switch to use safeLoad for loading YML files via file.readYAML. - Upgrade legacy-log to ~3.0.0. - Upgrade legacy-util to ~2.0.0. v1.2.1 date: 2020-07-07 changes: - Remove path-is-absolute dependency. (PR: gruntjs/grunt#1715) v1.2.0 date: 2020-07-03 changes: - Allow usage of grunt plugins that are located in any location that is visible to Node.js and NPM, instead of node_modules directly inside package that have a dev dependency to these plugins. (PR: gruntjs/grunt#1677) - Removed coffeescript from dependencies. To ease transition, if coffeescript is still around, Grunt will attempt to load it. If it is not, and the user loads a CoffeeScript file, Grunt will print a useful error indicating that the coffeescript package should be installed as a dev dependency. This is considerably more user-friendly than dropping the require entirely, but doing so is feasible with the latest grunt-cli as users may simply use grunt --require coffeescript/register. (PR: gruntjs/grunt#1675) - Exposes Grunt Option keys for ease of use. (PR: gruntjs/grunt#1570) - Avoiding infinite loop on very long command names. (PR: gruntjs/grunt#1697) v1.1.0 date: 2020-03-16 changes: - Update to mkdirp ~1.0.3 - Only support versions of Node >= 8

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump y18n from 4.0.0 to 4.0.1

    Bump y18n from 4.0.0 to 4.0.1

    Bumps y18n from 4.0.0 to 4.0.1.

    Changelog

    Sourced from y18n's changelog.

    Change Log

    All notable changes to this project will be documented in this file. See standard-version for commit guidelines.

    5.0.5 (2020-10-25)

    Bug Fixes

    5.0.4 (2020-10-16)

    Bug Fixes

    • exports: node 13.0 and 13.1 require the dotted object form with a string fallback (#105) (4f85d80)

    5.0.3 (2020-10-16)

    Bug Fixes

    • exports: node 13.0-13.6 require a string fallback (#103) (e39921e)

    5.0.2 (2020-10-01)

    Bug Fixes

    5.0.1 (2020-09-05)

    Bug Fixes

    5.0.0 (2020-09-05)

    ⚠ BREAKING CHANGES

    • exports maps are now used, which modifies import behavior.
    • drops Node 6 and 4. begin following Node.js LTS schedule (#89)

    Features

    ... (truncated)

    Commits
    Maintainer changes

    This version was pushed to npm by oss-bot, a new releaser for y18n since your current version.


    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump elliptic from 6.5.2 to 6.5.4

    Bump elliptic from 6.5.2 to 6.5.4

    Bumps elliptic from 6.5.2 to 6.5.4.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • docs: Fix simple typo, childen -> children

    docs: Fix simple typo, childen -> children

    There is a small typo in out/async-dom/UnwrappedChildrenOfParent.js, src/async-dom/UnwrappedChildrenOfParent.js.

    Should read children rather than childen.

    opened by timgates42 1
  • Bump shell-quote from 1.7.1 to 1.7.3

    Bump shell-quote from 1.7.1 to 1.7.3

    Bumps shell-quote from 1.7.1 to 1.7.3.

    Release notes

    Sourced from shell-quote's releases.

    v1.7.2

    • Fix a regression introduced in 1.6.3. This reverts the Windows path quoting fix. (144e1c2)
    Changelog

    Sourced from shell-quote's changelog.

    1.7.3

    • Fix a security issue where the regex for windows drive letters allowed some shell meta-characters to escape the quoting rules. (CVE-2021-42740)

    1.7.2

    • Fix a regression introduced in 1.6.3. This reverts the Windows path quoting fix. (144e1c2)
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump y18n from 4.0.0 to 4.0.3

    Bump y18n from 4.0.0 to 4.0.3

    Bumps y18n from 4.0.0 to 4.0.3.

    Changelog

    Sourced from y18n's changelog.

    4.0.3 (2021-04-07)

    Bug Fixes

    • release: 4.x.x should not enforce Node 10 (#126) (1e21a53)

    4.0.1 (2020-11-30)

    Bug Fixes

    Commits
    Maintainer changes

    This version was pushed to npm by oss-bot, a new releaser for y18n since your current version.


    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
Releases(v1.0.21)
Owner
Guseyn Ismayylov
Author of Async Tree Pattern. Creator of EHTML.
Guseyn Ismayylov
The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web.

Bootstrap Sleek, intuitive, and powerful front-end framework for faster and easier web development. Explore Bootstrap docs » Report bug · Request feat

Bootstrap 161.1k Jan 4, 2023
Brail is a framework built on NextJS for developing email templates in React, and returning HTML that is compatible with major email clients.

Brail is a framework built on NextJS for developing email templates in React, and returning HTML that is compatible with major email clients. It aims to seperate the concerns of generating the emails and delivering them.

null 121 Jan 2, 2023
An open-source, self-hosted, low-code framework to build internal tools, web apps, admin panels, BI dashboards, workflows, and CRUD apps with YAML or JSON.

An open-source, self-hosted, low-code framework to build internal tools, web apps, admin panels, BI dashboards, workflows, and CRUD apps with YAML or JSON.

Lowdefy 2k Jan 4, 2023
NXPayload Converter is a program that allows you to create boot.dat files from Nintendo Switch payload files (.bin)

?? NXPayload Converter NXPayload Converter is a program that allows you to create boot.dat files from Nintendo Switch payload files (.bin) If you have

Murasaki 24 Dec 22, 2022
NativeScript empowers you to access native api's from JavaScript directly. Angular, Vue, Svelte, React and you name it compatible.

NativeScript empowers you to access native APIs from JavaScript directly. The framework currently provides iOS and Android runtimes for rich mobile de

NativeScript 22k Jan 4, 2023
🌟 DataFormsJS 🌟 A minimal JavaScript Framework and standalone React and Web Components for rapid development of high quality websites and single page applications.

?? Welcome to DataFormsJS! Thanks for visiting! ?? ?? ?? ?? ?? ?? 中文 (简体) 欢迎来到 DataFormsJS Español Bienvenido a DataFormsJS Português (do Brasil) Bem

DataFormsJS 156 Dec 8, 2022
Ember.js - A JavaScript framework for creating ambitious web applications

Ember.js is a JavaScript framework that greatly reduces the time, effort and resources needed to build any web application. It is focused on making yo

Ember.js 22.4k Jan 8, 2023
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

Supporting Vue.js Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome ba

vuejs 201.7k Jan 8, 2023
A JavaScript Framework for Building Brilliant Applications

mithril.js What is Mithril? Installation Documentation Getting Help Contributing What is Mithril? A modern client-side JavaScript framework for buildi

null 13.5k Dec 26, 2022
A framework for real-time applications and REST APIs with JavaScript and TypeScript

A framework for real-time applications and REST APIs with JavaScript and TypeScript Feathers is a lightweight web-framework for creating real-time app

Feathers 14.2k Dec 28, 2022
A rugged, minimal framework for composing JavaScript behavior in your markup.

Alpine.js Alpine.js offers you the reactive and declarative nature of big frameworks like Vue or React at a much lower cost. You get to keep your DOM,

Alpine.js 22.5k Dec 30, 2022
A no-dependency, intuitive web framework from scratch in Javascript

Poseidon ?? Intro Poseidon is, to use a nice description by Reef, an anti-framework. It's a a no-dependency, component-based Javascript framework for

Amir Bolous 45 Nov 14, 2022
hell.js 🚀 🚀 A JavaScript framework for the 🔥 next 🔥 generation. 🚀

hell.js ?? ?? A JavaScript framework for the ?? next ?? generation. ??

null 31 Oct 3, 2022
AngularJS - HTML enhanced for web apps!

AngularJS AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you use good old HTML (or HAML, Jade/Pug and

Angular 59.3k Jan 4, 2023
The worlds smallest fully-responsive css framework

FLUIDITY A fully responsive css framework that is impossibly small HTML is almost 100% responsive out of the box. This stylesheet patches the remainin

murmurs 1.1k Sep 24, 2022
An HTML5/CSS3 framework used at SAPO for fast and efficient website design and prototyping

Welcome to Ink Ink is an interface kit for quick development of web interfaces, simple to use and expand on. It uses a combination of HTML, CSS and Ja

SAPO 1.9k Dec 15, 2022
One framework. Mobile & desktop.

Angular - One framework. Mobile & desktop. Angular is a development platform for building mobile and desktop web applications using Typescript/JavaScr

Angular 85.7k Jan 4, 2023
The tiny framework for building hypertext applications.

Hyperapp The tiny framework for building hypertext applications. Do more with less—We have minimized the concepts you need to learn to get stuff done.

Jorge Bucaran 18.9k Jan 4, 2023