ResponsiveJS – How to include the library? – clientMap.js



ResponsiveJS – How to include the library? – clientMap.js

1 0


denisgursky.github.io


On Github denisgursky / denisgursky.github.io

ResponsiveJS

Hello, I'm going to talk about ReponsiveJS framework

ResponsiveJS

ResponsiveJS is our highspeed, easy-to-implement JavaScript framework that transforms your desktop website into a Responsive Design website, optimized across screen sizes for mobile and tablet.

The idea is simple, we're writing CSS and JS code to make a site looks well on devices

How to include the library?

Insert the library 5thfinger.responsive.js

Insert an inline script, that begins responsifying

To make it work you need to include two things the library script and an inline script, that begins the responsifying process

Simple including

Insert the following markup inside the <head> section

To minimize the impact on your site,

place the tag as close as possible the </head> tag.

  <script src="//your-hostname//5thfinger.responsive.js"
      type="text/javascript"></script>

  <script type="text/javascript">
    responsify.start({
      remoteDebug: false,
      mobileOnly: true,
      clientMapSrc: "//your-hostname/clientMap.js"
    });
  </script>
        
Here's an example. Read the slide.

Full Example

<html>
  <head>
    <!--here your scripts, styles, whatever-->
    <script src="//your-hostname//5thfinger.responsive.js"
        type="text/javascript"></script>

    <script type="text/javascript">
      responsify.start({
        remoteDebug: false,
        mobileOnly: true,
        clientMapSrc: "//your-hostname/clientMap.js"
      });
    </script>
  </head>
  <body>Here is your page</body>
</html>
It's is the same example, just to show you how it looks in the page markup

clientMap.js

Configuration object to setup project settings before executing client scripts

It's an object that allows setup setting in a declarative way

Example

  responsify.clientMap = {
    viewport: "",
    bounds: {
      phone: { maxWidth: 669 },
      tablet: { minWidth: 670, maxWidth: 1280 },
      desktop: { minWidth: 1281 }
    },
    controls: ["footerLinks"],
    sources: {
      timeout: 10000,
      js: [{ src: "./js/master.js", callback: "runMaster"}],
      css: [{ href:"./css/master.css" }]
    }
  };
        
This is how the client map usually looks. Let's consider we can do here and all available properties in detail

Viewport

Allows you to set your value for the viewport meta tag.

Default value:

width=device-width, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0, user-scalable=no

Using the viewport meta tag allows to control layout on mobile browsers. You can define what viewport the library adds to the page. Here's default viewport on the slide

Bounds

Declares ranges in pixels for the screen width

  bounds: {
    phone: { maxWidth: 669 },
    tablet: { minWidth: 670, maxWidth: 1280 },
    desktop: { minWidth: 1281 }
  }
        
Read the slide. You can define so many bounds, how much you need

Bounds

Ability to separate the behavior for different bounds

The library creates some media queries to manage visibility of elements

  //element1 is visible only for phones
  RD.boundManager.applyFor($(".element1-selector"), [bounds.phone]);

  //element2 is visible for all bounds except phone
  RD.boundManager.applyForOther($(".element2-selector"), [bounds.phone]);
        
Bounds abstraction is a good way to separate different behaviors for different screens widths. And provide the best UI/UX for any devices. The library internally creates some media queries to support this feature, and appends them as a style tag to the page. Read the example. The library provides API that allows you detect the current bound for example. And it fires an event when bound is changed.

Controls

List of controls the library loads

  controls: [
    "footerLinks",
    "fullSiteLink",
    "menuBlock"
  ]
        
The library provides a set of controls. You can use them to build UI/UX very quickly. Here you define which of the them you'd like to use, and controls will be loaded asynchronously. We'll consider the full list later on.

Sources

The heart of the clientmap

Defines where the code must be applied

  sources:{
    timeout:10000,
    js:[
      { src:"master.js", callback:"runMaster" },
      { src:"productList.js", contentCondition:[".products"],
          callback:"runProductList" },
      { src:"product.js", urlCondition:["product"],
          contentCondition:[".product"], callback:"runProduct" },
      { src:"iphone-ipad-only.js", uaCondition:["iphone", "ipad"],
          callback:"runIphoneIpadOnly" }
    ],
    css:[
      { href:"../css/master.css" },
      { href:"../css/productList.css", contentCondition:[".products"] },
      { href:"../css/product.css", urlCondition:["product"],
          contentCondition:[".product"] }
    ]
  }
        
Read the slide. It's a huge object, that has a lot of options. Let's look at them.

Sources:Options

Timeout

number of milliseconds for downloading the sources

the timeout is exceeded, the library reverts changes

This first option is timeout. Read the slides. I'll tell you what reverting changes really means in deep a bit later, but for now it's enough to know that it rollbacks some changes the library already did

Sources:Options

JS

  • src: location of the script
  • callback: a function is called after onReady event is fired
  • urlCondition: RegEx to check a page url
  • contentCondition: CSS selectors to check DOM
  • uaCondition: RegEx to check User Agent
  • customCondition: a function with custom logic, returns boolean
The JS property declares what scripts will be used to make the site looks well. It's an array, let's look at what attributes a single item may have. Read the slide.

Sources:Options

CSS

  • href: location of the scripts or styles
  • id: an unique identificator of the css file. Details
  • urlCondition: RegEx to check a page url
  • contentCondition: CSS selectors to check DOM
  • uaCondition: RegEx to check User Agent
  • customCondition: a function with custom logic, returns boolean
The CSS property declares what styles will be applied to the site. It's an array too, some attributes are the same, but some are different. Read the slide.

Conditions

All types of conditions are arrays, except customCondition

Condition is true, if any sub-condition in the array is true

Source is applied, if all conditions are true

Conditions say to the library can a source be applied to the page or not. All types of conditions are arrays, except customCondition. Let's call an item in a condition array - sub-condition. Read the slide.

Conditions

The following source is applied, when:

  • it is opened on iPhone or iPad
  • and the url contains 'product'
  • and it's Retina
  • and it has an element with class 'someElement'

  var isRetina = function(){
    return window.devicePixelRatio === 2;
  };
  //...
  sources:{
    js:[
      { src:"test.js", uaCondition:["iphone", "ipad"],
        urlCondition:["product"], customCondition: isRetina,
        contentCondition:[".someElement"], callback:"runTest" }
    ]
  }
          
Here's an example. Read the slide.

CSS Id

The library executes JS callbacks after the CSS file is loaded

clientMap.js

  sources:{
    css:[
      { href: "master.css", id: "master-css" }
    ]
  }
          

master.css

  link#master-css {
   	visibility: hidden;
  }
          

Sometimes you need to execute some code after styles are loaded and applied. Usually, it happens when you need to get a size of an element and then use it some how. The styles can affect on this size, you want to be sure that they are already applied. Bad news. Browsers don't provide onload event for the link tag as they do for the script tag. So there's no way on the box to know exactly when a CSS file is loaded. Good news. There's a workaround in the library that works across all browsers. Just two steps: 1) add an unique id attribute 2) add this css rule in the CSS file All javascript callback will be executed after the CSS file is loaded.

Lifecycle

can be divided into 3 phases

Read the slide. First happens when the browser loaded the library. Second when responsify.start method is called Third when callbacks are executed

Library loaded

Just 3 things happens here. It initializes some default values, then initializes helpers that used internally, and adds the viewport.

Defaults

  var defaults = {
    waitForJQueryTimeout: 30000,
    viewport: "width=device-width, minimum-scale=1.0, maximum-scale=1.0,"
        + " initial-scale=1.0, user-scalable=no",
    log: true,
    jQueryLink: "//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js",
    jQueryMinSupportedVersion: "1.8",
    formatDetection: false
  };
          

It's an object that used internally, it contains default values.

Responsify start

the following flow happens when responsify.start({...}) method is called

A lot of things happens in background when the method is called. In short, you pass some settings and it starts the responsifying process. But we're going to talk about in details.

Example

  responsify.start({
    clientMapSrc: "//your-hostname/clientMap.js"
    remoteDebug: false,
    mobileOnly: true,
    jQueryObject: "jQuery",
    formatDetection: false,
    log: true
  });
          

As you probably remember such code is placed in the inline script below the library script. Now I'll show what properties we have and may change here.

clientMapSrc

Required

Location of the clientmap file

It's the only one required property. Declares where the clientmap file is.

remoteDebug

Optional. Default: false

Based on jsconsole

Useful for simple debugging, logging on a mobile device

Read the slide. Internally, it adds a script to the page. The script is a bridge between your page and jsconsole. But it's much better to use native tools to debug.

mobileOnly

Optional. Default: false

Applies the responsive code only for touch devices

There's a simple condition that check touch. It checks ontouchstart property in the window object. So if you'll open the page on a laptop with touch screen you may see the responsive version of the page.

jQueryObject

Optional. Default: "jQuery"

Declares what object is used as jQuery

More details about jQuery

If you have jQuery that has a different name. By default, it jQuery in lower camelcase. You may provide the different name, it must be a string. The library tries to take it from the window object by the given name. If jQuery is loaded asynchronously for example via RequireJS or any other module loader, in this case library checks jQuery availability 30 seconds and then fails.

jQueryLink

Optional. Default: "//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"

Location of jQuery, that would be used

More details about jQuery

You may provide a link to load jQuery, be default it refers to the Google CDN.

formatDetection

Optional. Default: false

Adds meta tag format-detection

<meta name="format-detection" content="telephone=no"/>

By default, phone numbers look like hypertext links, you can tap to call a number. This options allows you set off this, and phone numbers will look like on desktop.

log

Optional. Default: true

Writes logs into the browser console

Read the slide.

Preparing

It starts from simple checking, the next slide tells what is this checking. If the checking is not passed, the library triggers 'cancelStart' event. If it's ok we move ahead, again init some helpers, then hide the content, then check the format detection options, and if it's true we add the meta tag. Now I'll show you what these blue items on the diagrams mean do.

Checking

  • is it started already?
  • does the browser support addEventListener
  • is mobileOnly enabled?
  • is fullSite enabled?

Read the slide. If all of these true, the checking is passed.

Hide Content

The library adds the code below to the <head>

  <style id="RDhideAll" type="text/css">
    html, body {
      background:none;
    }

    body>* {
      opacity:0;
      filter:alpha(opacity=0);
      position:absolute;
      left:-3000px;
    }
  <style>
          

The library adds this styles to the head tag. They remove background on body and html elements and move all body's child elements far away to the left

Loading

It's most difficult and long part of the process. Resolving jQuery and downloading the clientmap go in parallel. Once jQuery is resolved, it waits other things. When the clientmap is loaded, it loads JS & CSS sources and controls in parallel. Of course, controls loading happens only if you use them, and you declared it in the clientmap object. Let's take a look at resolving jQuery and other things happens there.

Resolve jQuery

It tries to use jQueryObject property, then jQueryLink, then take window.jQuery, then load from CDN. All of these steps check the jQuery version, the minimum supported version is 1.8 When any of these steps got jQuery with version greater or equal 1.8, jQuery is resolved and we go ahead. If after all of them the library didn't get jQuery, it reverts changes.

Sources

It checks that clientMapSrc is provided. Then creates media queries for chosen bounds, then filter sources by given conditions, load CSS and JS in parallel. Loading CSS means that the library adds a link tag, so the styles are applied asynchronously and it doesn't what when all files are loaded.

Revert Changes

What happens?

The Library removes

  • Viewport
  • Format Detection
  • Sources

and shows content

Read the slide.

Revert Changes

When happens?

when any from the list below fails

  • initializing remote debugging
  • downloading the clientmap
  • downloading JS source
  • downloading CSS source
  • resolving jQuery
  • checking CSS and JS in onReady

There many cases when it may happens. Read the slide. The last item related to the production version and I'm going to talk about it next.

Production version

JS and CSS code are concatenated and minified in a single file

It's usually called clientMap.js

Sources are not loaded separately

Users don't like to wait while the site loads. And our goal here is decreasing the loading time. The popular solution is decreasing amount of additional resources like scripts, css files, images, whatever which is loaded separately. And of course decreasing file sizes. Typical optimization for ResponsiveJS is 1) converting background images to base64 and include them in the css files 2) minifying CSS and JS 3) concatenate all of them in a single file So in the end we have just a single file, that is usually called clientMap.js

Production version

JS

clientMap object

  sources: {
    js: [{ src: "js/master.js", callback: "runMaster"}]
  }
          

Code in the same file, callback matches the first argument

  RD.clientFnManager.set("runMaster", function () {
    //do something
  });
          

Read the slide.

Production version

CSS

clientMap object

  sources: {
    css: [{ href: "css/master.css"}]
  }
          

Code in the same file, href matches the first argument

  RD.clientCssManager.set('css/master.css', 'body{ background: red; }');
          

The second argument is added to style tag

So if you add such JS code into your sources, the library won't load 'css/master.css' it adds a style tag with string inside that you pass as the second argument. You'll see how to do this automatically with GruntJS in the next training session. Let's back to that checking that I mentioned couple slides before. Checks that all href's in the clientmap match resources in the clientCssManger same for JS callbacks and clientFnManager.

Finishing

In the end, it adds viewport from the clientmap, attaches handler to resize event, triggers ready event, and removes the style tag that hides body.

Resize Handler

memories the current screen width

triggers resize event

triggers boundChange event

Read the slide.

Raise Ready

triggers ready event

adds CSS sources to the page, in the production version

executes JS callbacks

  • if a callback throws an exception, the next callback won't be executed

This ready is not the DOM ready event, it's a library event. Read the slide.

Callbacks

a callback is executed one time

setTimeout's, setInterval's, event handlers live until the next page loading

Read the slide. Whatever you write in callbacks will work from there.

Controls

The library provides a set of controls. You can use them to build UI/UX very quickly. Almost all of them has good tutorials with examples. Let's see how they looks

footerLinks

creates a collapsible menu of key links you would typically find at the bottom of a page

Mobile Tablet Desktop

fullSiteLink

creates a button that allows switch off/on responsive

Mobile Tablet Desktop

menuBlock

is a simple way to show a website menu on a mobile device

Mobile Tablet Desktop

menuCollapsible

is a simple and structured way to display information on a mobile device

Mobile Tablet Desktop

pinchZoom

allows you to apply zoom to elements

Mobile Tablet Desktop

sidebar

creates a panel that hides behind the left side of a page

Mobile Tablet Desktop

simplePopup

is an overlay adapted for a mobile device, a use can scroll the content inside the popup

Mobile Tablet Desktop

slider

is a touch-enabled image gallery that allows you to scroll back and forth through different images

Mobile Tablet Desktop

Documentation

The library is fully documented using JSDoc

Docs are here or here

Documentation are available by these links.

Documentation

Read the slide. Show docs by clicking the links.