Giter VIP home page Giter VIP logo

hairdresser's Introduction

logo.png

A universal js library for managing head DOM elements (title, link and meta)

Browser support includes every sane browser and IE8+. (IE8 with es5-shim)

NPM Version Linux Build Windows Build Coverage Status

Sauce Test Status

var hairdresser = Hairdresser.create();
hairdresser.override()
  .title('Hairdresser')
  .meta({ property: 'og:title' }, { content: 'Hairdresser' });

hairdresser.render();

Features

  • Manages <head>'s child elements (ex. <title>, <meta> and <link>)
  • Hierarchical state friendly API
  • Server-side rendering

Motivation

Independence from framework

There are already good projects for managing <title>, <meta> and <link> elements. Following are some of the projects:

Most of the projects depend on client-side frameworks like AngularJS or ReactJS. Using frameworks can make code shorter and simpler, but it also costs flexibility and maintainability. I think the cost exceeds the benefit. There are good framework independent libraries for sortable UI and drag and drop. Why not for <head> manipulation?

Hierarchical state friendly API

As <head>'s child elements represent state of the app, <head> manager should receive state change events and change <head> rendering function properly. For example, an app uses app name for <title> on root state, and uses title of the article for <title> on article showing state.

In most cases, app uses hierarchical state like this:

Root > Category > Sub category > Article List

Hierarchical architecture is popular (ex. file system), and can take advantage of URL's hierarchical representation. In fact, the strength of hierarchical state is not important. The thing is, hierarchical state is common for web apps and <head> manager should offer hierarchical state friendly API.

How to use

1. Get started with default values

Let's start by creating a Hairdresser instance.

// With new operator
var hairdresser = new Hairdresser();

// Or with static function
var hairdresser = Hairdresser.create();

Hairdresser manages one controller per DOM element in an override fashion. A controller defines when and how to render an element. To set default values, just call hairdresser.override and pass render parameter per element. render parameter is the first parameter of title method and the second parameter of meta and link methods.

hairdresser.override()
  .title('Hairdresser')
  .meta({ name: 'title' }, { content: 'Hairdresser' })
  .link({ rel: 'canonical' }, { href: 'https://example.com' });

This is <head> inner HTML that the above code expects.

<!-- Alphabetical order -->
<link rel="canonical" href="https://example.com"></meta>
<meta name="title" content="Hairdresser"></meta>
<title>Hairdresser</title>

render parameter can be a value which replaces element content or a function that returns the element replacing value. For example, following two examples change element in the same way.

// Example1 - Use static primitive string value.
hairdresser.override()
  .title('Hairdresser');

// Example2 - Use dynamic function return value.
hairdresser.override()
  .title(function () {
    return 'Hairdresser';
  });

As for <title>, there is no need of a selector because only one <title> can exist. render parameter of <title> should be or return a string value because title is string.

In case of <meta> and <link>, there can be multiple elements with the same tag name in DOM, so a selector is required. The first argument of meta and link function is the selector, which represents key-value attribute pairs. Similarly, render parameter of <meta> and <link> should be or return an object as key-value attribute pairs.

Now we should call hairdresser.render in order to make Hairdresser start manipulating DOM.

hairdresser.render();

2. Override controllers on state transition

When application state changes, you may want to change a controller to handle an element. For example, you want to set <title> to the default value on the main page, and want to set <title> to article title on article page. Then, you can override the controller for <title> like this:

var article = {
  title: 'My awesome article'
};

var override = hairdresser.override()
  .title(function () {
    return article.title;
  });

// Cancel override on leaving the article page.
onLeaveState(function () {
  override.restore();
});

Now <title> is set to article's title, My awesome article. You can go back to the previous controller by calling restore method.

In case of hierarchical state, you can override a controller multiple times when you traverse down multiple child states.

3. Trigger update

You can update <head> element in two ways.

One is manual function call. override.update updates all the elements in override.

var override = hairdresser.override()
  .title(getTitle);

onDataReceived(function () {

  // Manual update
  override.update();
});

The other one is using event listeners. A listener can be added to override and each element.

Many event emitter's listener adding functions return listener removing function. For those cases, to manage the removing function in a simple way, the return value of addListener is passed to removeListener as the second parameter.

// Use fbemitter (https://github.com/facebook/emitter)
var emitter = new EventEmitter();

// Listener per override
var override = hairdresser.override({
  addListener: function (listener) {
    return emitter.addListener('update.override', listener);
  },
  removeListener: function (listener, token) {
    token.remove();
  },
}).title(getTitle);

emitter.emit('update.override');

// Listener per element
var override = hairdresser.override()
  .title(getTitle, {
    addListener: function (listener) {
      return emitter.addListener('update.title', listener);
    },
    removeListener: function (listener, token) {
      token.remove();
    });
  });

emitter.emit('update.title');

4. Render to DOM or string

This library is universal. You can modify <head> DOM element on browser.

var hairdresser = Hairdresser.create();
hairdresser.override().title('Hairdresser');

// render() will render `<head>` DOM element,
// and watch further overrides.
hairdresser.render();

You can also get elements as a string value.

var hairdresser = Hairdresser.create();
hairdresser.override().title('Hairdresser');

var head = hairdresser.renderToString();
assert(head === '<title>Hairdresser</title>');

API

Refer to API documentation

Roadmap

Refer to Roadmap documentation

Examples

License

MIT

hairdresser's People

Contributors

pawsong avatar limchrm avatar

Watchers

Abdulhadi Havari avatar James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.