home.

tagged: html

Javascript: Create HTML with Javascript

If you create HTML with javascript you can
The first user case is handled by the new template literals. The second usecase is not. Although there are tricks around that but this post is not about that.
 
We want to be able to do

node("div")
node("div", "background-color: red")
node("div", "background-color: red", ["id", "an_id", "class", "something", "attribute", "value"])

With everything but the tag name optional. For example node("div", ["id", "hiya"]) is valid as is node("span").
 
We also want to add child nodes as a single node or an array of nodes or a mixture. These come after the tag name, optional style and optional attributes.

node("div",
  node("div")
)
node("div",
  node("div"),
  node("div")
)
node("div",
  [node("div"), node("div")]
)

node("div",
  node("div"),
  [node("div"), node("div")],
  node("div")
)

In addition we want to be able to optionally add event listeners. These come after the tag name, optional style and optional attributes.

node("div", 
  ["click", (event) => console.log("click"),
   "focus", (event) => console.log("focus")]
)

And it's annoying to type node("div") and not div() so let's fix that now.

function div() { 
  return node.apply(this, ["div"].concat([...arguments]))
}
function span() { 
  return node.apply(this, ["span"].concat([...arguments]))
}
etc...

Plus we need this for text

function text(str) {
  return document.createTextNode(str)
}

Finally here's the function that does all that:

function node() {
  var iterator = 0;
  var h = document.createElement(arguments[iterator++])
  if(arguments[iterator] && typeof(arguments[iterator]) === "string") h.style = arguments[iterator++];
  if(arguments[iterator] && arguments[iterator] instanceof Array
    && typeof(arguments[iterator][1]) === "string") {
    for(var i=0; i<arguments[iterator].length;) {
      h.setAttribute(arguments[iterator][i++], arguments[iterator][i++])
    }
    iterator++
  }
  if(arguments[iterator])
  for(var i = iterator; i < arguments.length; i++) {
    if(arguments[i] instanceof Array) {
      if(arguments[i][1] instanceof Function) {
        for(var j = 0; j < arguments[i].length; ) {
          h.addEventListener(arguments[i][j++], arguments[i][j++])
        }
      } else {
        arguments[i].forEach(node => h.appendChild(node))
      }
    } else {
      h.appendChild(arguments[i])
    }
  }
  return h
}

div(
  h4("color: blue", 
    text("click me"),
    ["click", () => alert("end of blog post")]
  )
)

(You can't set the style string to an empty string, since the DOM will freak out on seeing node.style = "")

javascript html


Javascript: Multiple pages and browser history navigation using plain js

You often want different pages in your web app with browser navigation.
 
Let's define the HTML. Each page will be a div with the page class and an id attribute that ends with _page. We'll describe the function event listeners later.

<div id="main_page" class="page">
    <p>
        Home page content
    </p>
    <div onclick="gotoPage('pagetwo')">
        Next page
    </div>
</div>
<div id="pagetwo_page" class="page">
    <div onclick="gotoPage(-1)">
        Previous page
    </div>
    <p>
        Page two content
    </p>
</div>

The gotoPage function will:
  1. Go to a new page using the location hash, i.e. gotoPage("newpage") will go to "localhost/#newpage"
  2. Go to previous page when -1 is passed
  3. If this is the first load of the page, gotoPage(-1) will go to main_page instead.
  4. If no argument is passed, we refresh the current page
  5. Allow us to go to previous page with the browser back button i.e. if we're on "localhost/#newpage" then the back button will take us to "localhost/"
function gotoPage(hash) { var go = (hash) => { // Check if this conflicts with something in your app history.state = "from_webapp" location.hash = hash } // if come from another page in our webapp, let's go back to previous page if(hash == -1 && history.state == "from_webapp") history.back() // if we haven't used gotoPage() before (i.e. this is a direct link therefore no "from_webapp") // then let's go to default page on go(-1) else if(hash == -1 ) go("") else if(hash) go(hash) else window.newfivefour.onpopstate() }
 
We'll see what window.newfivefour.onpopstate() refers to in a moment.
 
We'll now setup our logic, setupPages(). The first thing we'll do it hide all divs with the .page class. Then on each time go() changes the location hash we'll call a function.
 
Each run of this function will then hide all the element again and show a div based on the page name. Going to go("messages") will unhide <div id="messages_page">. If the location hash is blank or "#" we'll show the <div id="main_page>.
 
setupPage will take an object whose properties relate to the main of a page id, i.e. <div id="pagetwo"> will relate to { "#pagetwo" : ... }, and the values will be functions.
 
So each time the function inside setupPages run it will check this object against the page we're visiting and then run the functions therein, so you can define javascript functions to run when a page is loaded.
 
Here's the whole thing

<html>
  <body>
    <div id="main_page" class="page">
      <p>
        Home page content
      </p>
      <div onclick="gotoPage('pagetwo')">
        Next page
      </div>
    </div>
    <div id="pagetwo_page" class="page">
      <div onclick="gotoPage(-1)">
        Previous page
      </div>
      <p>
        Page two content
      </p>
    </div>
  </body>
  <script>
    setupPages({
      "default": () => console.log("main page"),
      "#pagetwo": () => console.log("page two")
    })


    function gotoPage(hash) { 
      var go = (hash) => {
        // Check if this conflicts with something in your app
        history.state = "from_webapp"
        location.hash = hash
      }
      // if we've not directly linked to the page, let's go back to previous page
      if(hash == -1 && history.state == "from_webapp") history.back()
      // if we haven't used gotoPage() before (i.e. this is a direct link therefore no "from_webapp")
      // then let's go to default page on go(-1) 
      else if(hash == -1 ) go("") 
      else if(hash) go(hash)
      else window.newfivefour.onpopstate()
    }
    function setupPages(onLoadPageHash) {
      if(!window.newfivefour) window.newfivefour = {}
      var hideAllPages = () => {
        var pages = document.querySelectorAll(".page");
        for(var i = 0; i < pages.length; i++) pages[i].style.display="none";
      }
      hideAllPages()
      window.newfivefour.onpopstate = () => {
        hideAllPages()
        var hash = location.hash;
        if(hash == "" || hash == "#") {
          document.querySelector("#main_page").style.display = "block"
          if(onLoadPageHash && onLoadPageHash["default"]) onLoadPageHash["default"]()
        } else {
          if(onLoadPageHash && onLoadPageHash[hash]) onLoadPageHash[hash]()
          var page = document.querySelector(hash + "_page")
          if(page) {
            page.style.display = "block"
          }
        }
      }
      window.addEventListener("popstate", window.newfivefour.onpopstate)
      gotoPage() // Go to the default page
    }
  </script>
</html>

javascript html


Use html to order a border with a title around things

You can group items with a border in HTML using fieldset and you can also give that border a title using legend.
 
The title breaks the border briefly at the top.
 
Here's an example which you can use to impress your friends, family, dogs, cats and potential parliamentary representatives.

<fieldset style="border: 1px dashed black">
  <legend>Ladies and gentlemen we are floating in space</legend>
  Sup
</fieldset>

css html


HTML, CSS: Make a div float in the middle of page

First make the position of the div fixed. We'll place it at the bottom of our screen by setting the bottom to 5px.
 
We make it so the div starts from the middle of the screen by setting the left property to 50%.
 
But this won't make it exactly in the middle of the screen, of course, since this mean it starts from the middle of the screen, not that its centre point is in the middle of the screen.
 
To properly centre the div use the transform property to move the div half its width to the left.

  <div
    style="position: fixed; bottom: 5px; left: 50%; transform: translateX(-50%);">
    I am centered. Rejoice.
  </div>

css html


Formatting/Beautify HTML and Javascript from the command line

First, install the js-beautify package from npm.

sudo npm -g install js-beautify

Now make some dodgily formatted HTML with javascript

echo '<html></body></body><script> var i = 0; var j = 1; </script></html>' > dodgy.html

js-beautify takes -f - to find things from the command line, and --type html to say the javascript is embedded in some HTML. Finally we pipe to less for viewing.

cat dodgy.html | js-beautify -f - --type html

The output is:

<html>
</body>
</body>
<script>
    var i = 0;
    var j = 1;
</script>
</html>

You can add -o dodgy.html to replace the original text in dodgy.html.

unix javascript html beautify npm

Page 1 of 2
next