f w h

Mark Your Spot on a Page – Bookmarklet

Recently, I was trying to work my way through an HTML-based online book. It became a pain to find my spot again when I had to close the browser or reboot the computer for various reasons. So, I created a bookmarklet to help me find my spot again when I return to the page. The bookmarklet adds a small box in the upper right corner of the window with buttons to add or clear bookmarks. When you click the ADD button, you’ll be prompted to name the bookmark, which will then be added to the list. Bookmarks are stored in local storage, so they will persist from session to session. You’ll just have to click the bookmarklet again to reload them.

Go HERE to get the bookmarklet. Full code is below:


function bm_go(){

  var bm_block;

  bm_block = document.createElement('div');
  bm_block.classList.add('bm_class');
    bm_block.style.width = '100px';
    bm_block.style.minHeight = '33px';
    bm_block.style.position = 'fixed';
    bm_block.style.padding = '5px';
    bm_block.style.top = '10px';
    bm_block.style.right = '10px';
    bm_block.style.backgroundColor = 'white';
    bm_block.style.fontFamily = 'Arial, sans-serif';
    bm_block.style.color = 'black';
    bm_block.style.borderRadius = '5px';
    bm_block.style.border = '1px solid #999';
    bm_block.style.zIndex = '10000000';

  var bm_add_button = document.createElement('div');
  	bm_add_button.classList.add('bm_add_button');
    bm_add_button.style.display = 'inline-block';
    bm_add_button.style.height = '33px';
    bm_add_button.style.width = '45%';
    bm_add_button.style.border = '1px solid #999';
    bm_add_button.style.fontSize = '15px';
    bm_add_button.style.textAlign = 'center';
    bm_add_button.style.lineHeight = '33px';
    bm_add_button.style.cursor = 'pointer';
    bm_add_button.style.boxShadow = '2px 2px #666';
    bm_add_button.innerText = 'ADD';
  bm_block.appendChild(bm_add_button);

  var bm_clr_button = document.createElement('div');
  	bm_clr_button.classList.add('bm_clr_button');
    bm_clr_button.style.display = 'inline-block';
    bm_clr_button.style.height = '33px';
    bm_clr_button.style.width = '45%';
    bm_clr_button.style.border = '1px solid #999';
    bm_clr_button.style.fontSize = '15px';
    bm_clr_button.style.textAlign = 'center';
    bm_clr_button.style.lineHeight = '33px';
    bm_clr_button.style.cursor = 'pointer';
    bm_clr_button.style.boxShadow = '2px 2px #666';
    bm_clr_button.style.marginLeft = '5%';
    bm_clr_button.innerText = 'CLR';
  bm_block.appendChild(bm_clr_button);

  var bm_message = document.createElement('div');
  	bm_message.classList.add('bm_message');
    bm_message.style.marginTop = '5px';
    bm_message.style.marginBottom = '5px';
    bm_message.style.fontSize = '10px';
    bm_message.style.textAlign = 'center';
    bm_message.innerText = 'Click "ADD" to set bookmark at current scroll position.';
  bm_block.appendChild(bm_message);
    
  	document.body.appendChild(bm_block);
  
  var bm_list_init = JSON.parse(localStorage.getItem('bm_list')) || [];
   
  function bm_pop_list(list){
  	
    var rm_bm = document.querySelector('.bm_bm_list');
    if (rm_bm) rm_bm.parentNode.removeChild(rm_bm);
    
    var bm_bm_list = document.createElement('ul');
    bm_bm_list.classList.add('bm_bm_list');
    bm_bm_list.style.paddingLeft = '0';
    
    for (var i = 0; i < list.length; i++){

      var bm_list_item = document.createElement('li');
      bm_list_item.classList.add('bm_list_item');
      bm_list_item.innerText = list[i].name;
      bm_list_item.setAttribute('data-x', list[i].x);
      bm_list_item.setAttribute('data-y', list[i].y);
      bm_list_item.style.marginLeft = '0';
      bm_list_item.style.listStyleType = 'none';
      bm_list_item.style.cursor = 'pointer';

      bm_list_item.addEventListener('click', function(){

      	bm_go_to_location(bm_list_item);

      });

      bm_bm_list.appendChild(bm_list_item);

    }
    
    bm_block.appendChild(bm_bm_list);

  }
  
  bm_pop_list(bm_list_init);
  
  function bm_go_to_location(item){

  	window.scrollTo(item.getAttribute('data-x'), item.getAttribute('data-y'));

  }
  
  function bm_add_item(){

  	var bm_get_name = prompt('Enter Bookmark Name', 'bookmark'),
      	bm_get_x = window.pageXOffset,
        bm_get_y = window.pageYOffset;
    var bm_list = JSON.parse(localStorage.getItem('bm_list')) || [];

    bm_list.push({
    	name: bm_get_name,
      x: bm_get_x,
      y: bm_get_y
    });

    localStorage.setItem('bm_list', JSON.stringify(bm_list));
    bm_pop_list(bm_list);

  }
  
  function bm_clear(){

  	localStorage.removeItem('bm_list');
    bm_pop_list([]);

  }
  
  bm_add_button.addEventListener('click', bm_add_item);

  bm_clr_button.addEventListener('click', bm_clear);
  
}

var bm_ = new bm_go();

Display Viewport Size Bookmarklet

Chrome has a nice little overlay shows the viewport size when you resize if you have the developer tools open. For whatever reason, it stopped working on me for a short while. It was a bit frustrating, because of course it would decide not to work right when I needed it most.

So, why not recreate the magic?

Get the bookmarklet here

Original, uncompressed code below:


function vp_getViewport(){
  this.w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
  this.h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);

  this.output = {
    w: this.w,
    h: this.h
  };

  return this.output;
}
function vp_init(){
  var e = document.createElement('div');
  e.classList.add('vp_vpElement');
  e.style.backgroundColor = '#aaa';
  e.style.border = '1px solid black';
  e.style.padding = '2px';
  e.style.fontSize = '12px';
  e.style.position = 'fixed';
  e.style.top = '10px';
  e.style.right = '10px';
  e.style.zIndex = '1000000';
  document.body.appendChild(e);
}
vp_init();
function vp_showSize(viewport){
  var e = document.querySelector('.vp_vpElement');
  e.innerHTML = viewport.w + ' x ' + viewport.h;
}
window.addEventListener('load', function(){vp_showSize(vp_getViewport());});
window.addEventListener('resize', function(){vp_showSize(vp_getViewport());});

Simple Mobile Detection for JavaScript

One common question I see asks how one might conditionally run JavaScript based on screen size. There are a number of use cases for this, and there are a couple ways to go about it.
One easy way, as I wrote about almost exactly three years ago is to detect a CSS property based on a media query.
Another possibility is to use JavaScript to pull the size of the browser’s viewport. To make things easy, we can package everything in a neat little function that returns an object with the viewport details.


function viewport(){
  this.w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
  this.h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
  
  this.orientation = this.w > this.h ? 'landscape' : 'portrait';

  this.output = {
    w: this.w,
    h: this.h,
    orientation: this.orientation
  };

  return this.output;
}

The function can then be used in a number of ways.



// Conditionally do a thing inside a function
function doAThing(){
  if(viewport().w < 480){
    // Do a thing
  }
}

// Do a thing when the browser is resized
window.onresize = function(){
  if(viewport().orientation == 'portrait'){
    // Do a thing
  }
}

UPDATE July 2017: JS matchMedia API

Recently, SitePoint updated one of their 2011 posts to recommend this API.
In short, matchMedia returns a mediaQueryList object, which has a .matches() method attached to it. Passing a media query formatted the same as a CSS media query will return a boolean based on whether the query matches.
Read more about it on SitePoint’s How to use Media Queries in JavaScript.

NiceMenu – A JavaScript Responsive Menu for Multiple Menus

On a recent build, I needed a menu system like the impressive MeanMenu. Unfortunately, MeanMenu doesn’t support multiple menus. One fork of MeanMenu allows for multiple menus, though they present as multiple mobile menus, which I thought looked horrible. So, I thought, I’ll just roll my own.

NiceMenu isn’t, perhaps as polished as MeanMenu as far as presentation, but it will convert multiple menus into one responsive mobile menu.

Check out this Gist. Intructions for use are in the comments in the head of the JavaScript file.

The Poor Man’s FitText – JavaScript Text Size Adjustment

Dave Rupert’s FitText is a great tool for inflating or deflating type for responsiveness. I do find, however that it’s a bit finicky for certain cases, particularly if you want your text to fill the width of the space completely regardless of height. For a recent project, I wrote this script, which does exactly that by looping through the container’s width, checking it against the parent and adding to (or subtracting from) the font size until the container’s width matches the parent minus an offset.

The script currently uses jQuery, because I was already using it on the project. I will likely add a vanilla JS version in the near future.

The script requires that the container element be set to display:inline or inline-block.

See this Gist for the code. Instructions on how to implement it are in the file’s comments.

« Previous PageNext Page »