Tag Archives: Javascript

Installing the Brackets-ESLint NPM package

07 Jan 2017

If you are interested in an ES6 linter for Brackets there is a plugin called “Brackets-ESLint” that will do the job. However, it cannot be installed like any other Brackets plugin. You must first install a plugin called “Brackets-npm-registry” which functions similarly to the Brackets plugin manager but for Brackets-specific NPM modules.

The Brackets-npm-registry Plugin

Visit the following URL and read through the installation instructions for your platform. Note that on Windows you may have to manually navigate to your AppData directory.

Note that installation may take a few minutes.

The Brackets-eslint Plugin

Once “Brackets-npm-registry” is installed you will notice a new icon in the Brackets plugin bar:

eslint_01

Clicking the plugin reveals the “Brackets-npm-registry” module manager:

eslint_02

Scroll through the list and locate “ESLint” – install the plugin (this may also take some time to complete)

Once installation is complete close the installation window, then close the NPM module manager, and then restart Brackets (F5 on Windows).

Working with ESLint

Upon installing ESLint and restarting Brackets you may see linting issues within the left gutter of opened JS files such as can be seen in the image below:

eslint_03

Place the cursor above the red/yellow icons wihtin the left gutter to reveal a tool-tip explaining the linting issue. Alternatively you can toggle the display of the complete list of issues at the bottom of your editing window (also visible within the above image).

Configuring the Linter

Comments can be added to code to configure the linter. Of particular interest is the ability to instruct the linter to ignore a line of code. For example, this JS comment will remove the line it sits on from linting:

// eslint-disable-line

For example, note the following image and how by virtue of the red “X” icon in the gutter that there is a linting issue for that line:

eslint_04

To tell the linter to ignore the line we add the comment to the end and thus the issue goes away:

eslint_05

For further configuration options, including specifying blocks of code to ignore and configuring the linter via in-code comments see the following guide:

Specifying your Preferred Linter

You may not want to use ES6 linting for your ES5-based projects. In that case you’ll want to update Bracket’s preferences file per the description here to use your preferred linter.

Brightcove Embed Code and Events

10 Mar 2016

Another unique thing for me today – this time getting the Brightcove media player playing in a CBT that we’re developing. I originally setup the framework for this project and handed it off to other developers to complete but it has come back around to me since incorporating the Brightcove video player turned out to be problematic.

When the project landed back at my desk the video wasnt working and the PM was waiting for the client to send over the Brightcove iFrame code (the client didnt reveal they had a brightcove account until later). The iFrame was easy to setup but the assumption that it was what the project required was wrong – we’re hiding the navigation thereby forcing the end-user to watch the video which means we need to register some sort of “video end” event so that we know when to re-enable the UI. Since the iFrame’s source came from another domain we of course ran afoul of the cross domain policy preventing any interaction with the iFramed contents.

Digging into Brightcove’s docs I saw the “embed” option and started down that path: first, I needed to embed the code, next I needed to register the desired event.

Embed the Video HTML

I didn’t see the Brightcove console but from what the client gave us I could tell that there must be a section that provies sample embed code. You will want that code as it contains the Video ID (UID for the video), Account number (your Brightcove account), and the Player value (tells the Brightcove JS which video tag to use).

  

For my specific implementation the above was kept in an external HTML template file. I then pulled it and updated the necessary values. Once the HTML was ready to be inserted a simple $(‘#my-element-ID’).html(template-code-here) added it to the page.

Note that the video ID should must be inserted into the above for this to work (well, for this particular way of doing things) as it tells the Brightcove JS what video to use. What happens next is that we create a video player instance.

Init the Video

Per the Brightcove docs they create a script element, assign values to various properties and then add it to the page. A few things to note:

  1. We need to know when the Brightcove script has loaded
  2. We need to create a reference to the video player
  3. We need to assign a callback to the video player’s ended event

So with that in mind here’s the function I wrote (note the comments).

...
  var bc = function(accountID,playerID){
    var that = this;
    this.mPlayer = null;
    this.brightcove = {
      accountId : accountID, // your account ID here
      playerId : playerID // your player ID here
    }

    function addBrightCoveScript(){
      // create the element
      var s = document.createElement('script');

      // add the element to the page
      $('#my-wrapper').append(s);

      // set the onload
      s.onload = function(e){

        // the script has loaded, now lets detect the video player instantiation
        videojs('mPlayer').ready(function(){

          // cool, we know that the video player exists, lets get a reference to it
          that.mPlayer = videojs('mPlayer');

          // using the reference lets add a listener, in this case we are listening for the "ended" event
          that.mPlayer.one('ended',function(e){
            // the video has ended - do something here  
          });
        });
      };

    // now update the script tag
    s.src = '//players.brightcove.net/' + that.brightcove.accountId + '/' + that.brightcove.playerId + '_default/index.min.js';
  }
...

You will see what appears to be a typo: that.mplayer.one. The “one” is not a typo, per the Brightcove API registering an event with the “one” method will result in the listener detecting the event a single time. When that happens the listener removes itself thereby relieving me of the burden of doing it myself.

Following the above you should be good to go for modern HTML5-capable browsers.

Replacing Logical OR with Void and Logical AND

09 Sep 2015

I enjoy perusing other people’s code to see how they approach whatever it is that they are trying to solve. The follow simplified function caught my eye:

function someFunc(a){
   void 0===a.prop&&(a.prop=20);
}

Looks like some esoteric stuff but makes a lot of sense when written like this:

function someFunc(a){
    a.prop = a.prop || 20;
}

Functionally these two expressions mean the same thing. The difference is that the author of the first line is being clever 😉

The two expressions listed above read as follows in plain english: if a.prop is equal to undefined then create the property if it doesn’t exist and set its value to 20, or just set its value to 20..

The second example is much easier to read but the first is what we’re interested in so lets dissect its meaning.

First, this part needs to be understood:

void 0

This represents the global primitive property undefined. Why write it like this? Well, it used to be that you could overwrite undefined by design or by mistake meaning that you could never rely on it being what it should be (though usually you could) – writing it like this guarantees that you would always be dealing with the true undefined primitive value. Modern browsers don’t allow you to do overwrite undefined anymore.

Next is:

===

Which of course is the strict equal operator which checks to ensure that the operands or not only equal but of the same type.

Next:

a.prop

Of course this is a reference to the value held by the prop property of the a object.

So then, the author is comparing undefined to a.prop. This will return true or false. Ok, not so clever until we get to the next part:

&&(a.prop=20)

This is where it all comes together – note the logical AND operator &&. As you would expect it evaluates the expression on the left first and this is the key to how this bit of code works. These are the two possible outcomes of evaluating the left expression:

  • For the expression void 0===a.prop&&(a.prop=20);

    1. if a.prop is undefined then we must evaluate the expression on the right! Since the right operand is grouped by parenthesis it must first be evaluated to determine its truthiness. By evaluating it we are setting a default value for a.prop.
       
    2. if a.prop is not undefined then the left operand is false and nothing happens! Consider that both operands of the logical AND operator are evaluated only if the left operand is true. If the left operand is false then the right operand is ignored.

Pretty cool way of making use of the && operator!

As a side note, if the property was missing from the object we would also get undefined so the code here would first create the property then set its default value.

Creating Slideshows with iScroll 5

05 Jul 2015

iScroll has features that make it useful beyond just scrolling – among many uses it can be used to create slide shows. I created one today at work and am sharing the entire process here. I already had certain parts of this done for other parts of my application so it took me about 10 minutes to get everything wired up. Since this example starts from ground zero it will take a little longer.

Start with your layout

This demo will have four slides and we’ll need them in an unordered list, so we will start with this:

<ul>
	<li><img src="images/image_1.jpg" height="177" width="284" /></li>
	<li><img src="images/image_2.jpg" height="177" width="284" /></li>
	<li><img src="images/image_3.jpg" height="177" width="284" /></li>
	<li><img src="images/image_4.jpg" height="177" width="284" /></li>
</ul>

iFramed below is a page with the above code:

Ok, well, thats a start. We’ll be making a horizontal scroller so we need to style this list into a horizontal line using this CSS:

li {
	list-style-type: none;
	margin: 0px;
	padding: 0px;
	float:left;
}
ul {
	width: 1136px;
	margin: 0px;
	padding:0px;
}

A couple things to note:

  • Notice the UL width – since I’m essentially using it as the “wrapper” for the LI elements I need to set the width to equal the total width of all of the slides so that the list items can layout out in the desired manner.
  • I’m floating the list elements instead of setting their display to “inline-block” to be friendlier with old IE

So then, below is the result (scrolling in the iFramed example is on, thus the horizontal scroll bar):

Setup for iScroll

Next we need to setup everything for iScroll which means that we need to create a wrapper around our horizontal thumbnail list and then style it appropriately. Note these three things:

  1. As mentioned I’ve set the width of the UL element so that its width equals the total width of all of the slides since it is the element that will be scrolled ***inside*** of the wrapping div.
  2. The wrapping div has an id of “slideshow” and is styled such that its “viewport” is the same dimensions as a single slide. Note also that it’s overflow is set to “hidden”. If the UL element didn’t have its width set the wrapping div would have forced each slide to stack which is not what we want – we want the slides to lay in a single row.
  3. Within the CSS note the position:relative lines on both the UL and the #slideshow – these are necessary so that iScroll can do the calculations needed to get everything to work. If you forget about this your iScroll wont work at all.
<head>
<style type="text/css">
	li {
		list-style-type: none;
		margin: 0px;
		padding: 0px;
		float:left;
	}
	
	ul {
                position: relative;
		width: 1136px;
		margin: 0px;
		padding:0px;
	}
	
	#slideshow{
		position: relative;
		height: 177px;
		width: 284px;
		overflow: hidden;
	}
</style>

</head>
<body>
	<div id="slideshow">
		<ul>
			<li><img src="images/image_1.jpg" height="177" width="284" /></li>
			<li><img src="images/image_2.jpg" height="177" width="284" /></li>
			<li><img src="images/image_3.jpg" height="177" width="284" /></li>
			<li><img src="images/image_4.jpg" height="177" width="284" /></li>
		</ul>
	</div>
</body>

The following is the result:

Add iScroll

Unlike prior versions iScroll 5 has its own website from which you can download the library at http://iscrolljs.com/. Below is an example of adding it to a page.

<script type="text/javascript" src="js/iscroll.js"></script>

Next we need to initialize the iScroll on our “slideshow” wrapper. We can do so once the page has been loaded like so (jQuery users can substitute jQuery’s document.ready instead). More information on initializing iScroll can be found here.

That’s it – we currently have a functional iScroll – not yet a slideshow, but we’re getting there. Below is the javascript that made it happen followed by the iFramed example.

Of note here is the iScroll configuration object found on line 7. The scrollX property’s “true” value tells iScroll to scroll horizontally.

<script type="text/javascript" src="js/iscroll.js"></script>
<script type="text/javascript">
  ;(function(ns){
	var _iscroll = null;
	ns.init = function(){
		_iscroll = new IScroll('#slideshow',{
			scrollX: true
		});
	}
  })(this.slideshow = {});
  (function(){
	if(window.addEventListener){
		window.addEventListener('load',slideshow.init,false);
	} else{
		window.attachEvent('onload',slideshow.init); //IE
	}
  })();
</script>

Swipe with your finger or your mouse to see the iScroll work.

Configuring iScroll

Ok, now we start getting into the things that will make our slideshow really work. First, lets make iScroll behave a little differently, lets make it snap to each slide instead of scrolling past slides when you swipe. iScroll has 2 properties that we can pass via a configuration object that will tell it to a) snap to an element and b) not overscroll past the element. They are snap and momentum where the former’s value will be set to li since we are snapping to those elements and for the later we’ll use a value of false as we want to disable overswiping.

The adjusted script:

<script type="text/javascript" src="js/iscroll.js"></script>
<script type="text/javascript">
  ;(function(ns){
	var _iscroll = null;
	ns.init = function(){
		_iscroll = new IScroll('#slideshow',{
			scrollX: true
			snap:'li',
			momentum:false
		});
	}
  })(this.slideshow = {});
  (function(){
	if(window.addEventListener){
		window.addEventListener('load',slideshow.init,false);
	} else{
		window.attachEvent('onload',slideshow.init); //IE
	}
  })();
</script>

Give it a try with these new settings:

SPECIAL NOTE: All these examples are iFramed – so if you do a click-drag with a mouse and drag outside of the iFrame then things get kind of weird. This is normal. The explanation is that since you click-dragged outside of the iFrame itself the window within the iFrame does not know that you released the mouse button. Remember: This is a tutorial with “tightly iFramed” examples. To properly experience these examples try to not be so dramatic with your click-swipes 😉

Add next / previous buttons

Slideshows typically have back and next buttons. Lets add them to our slideshow – we’ll start with some basic layout, we’ll have a left and right button on top of the slide show. Each button is a div and will be positioned over the slideshow on the left and right edges.

Here’s the CSS that accomplishes this followed by the HTML:

	#btnleft, #btnright {
		position:absolute;
		top: 70px;
		height: 40px;
		width: 36px;
		z-index: 100;
		background-size:contain;
	}
	#btnleft{
		background-image: url(images/slideshow_left_arrow.png);
		left: 8px;
	}
	#btnright{
		background-image: url(images/slideshow_right_arrow.png);
		left: 255px;;
	}

And the new html – the button divs are added after the slideshow wrapper:

	<div id="slideshow">
		<ul>
			<li><img src="images/image_1.jpg" height="177" width="284" /></li>
			<li><img src="images/image_2.jpg" height="177" width="284" /></li>
			<li><img src="images/image_3.jpg" height="177" width="284" /></li>
			<li><img src="images/image_4.jpg" height="177" width="284" /></li>
		</ul>
	</div>
	<div id="btnleft"></div>
	<div id="btnright"></div>

This is the result:

Add event handlers to the buttons

You should have noticed by now that I’ve made no mention of jQuery thus far and in fact avoided it for the onload event that inits our iScroll. I didn’t want to use jQuery since it would mean using a big fat library to do trivial things. I know everyone likes jQuery so I’ll make a jQuery version that you can download at the end of this article. In the meantime your take-aways should be how to use iScroll not necessarily how to use jQuery for event delegation or whatever. That said, there are more iSrcoll things to learn which we will get to in a moment.

Back on topic, we need to wire up the “back” and “next” buttons. I’ll first wrap everything in a div and then apply the listeners to that wrapping element. The following code does this for us, click the example that follows the code sample to see it work.

The updated init function:

	ns.init = function(){
		_iscroll = new IScroll('#slideshow',{
			scrollX: true,
			snap:'li',
			momentum:false
		});
		// add event listeners
		if (window.addEventListener){
			document.getElementById('slideshow_wrapper').addEventListener('click',ns.doNav,false);
		} else{
			window.attachEvent('onload',slideshow.init); //IE
		}
	};
	ns.doNav = function(e){
		alert('clicked ' + e.target.id);
	};

And the updated HTML with a DIV element with id “slideshow_wrapper” wrapping everything:

	<div id="slideshow_wrapper">
		<div id="slideshow">
			<ul>
				<li><img src="images/image_1.jpg" height="177" width="284" /></li>
				<li><img src="images/image_2.jpg" height="177" width="284" /></li>
				<li><img src="images/image_3.jpg" height="177" width="284" /></li>
				<li><img src="images/image_4.jpg" height="177" width="284" /></li>
			</ul>
		</div>
		<div id="btnleft"></div>
		<div id="btnright"></div>
	</div>

Click the arrows….

What I’ve done is set things to capture the click events as they bubble up the DOM to the event listeners (a technique referred to as event delegation).

Add logic to the navigation buttons

Our buttons will advance the slideshow either forward or backward. To do this we need to be able to determine the direction the user wants to go. If you clicked the navigation buttons in the above example you can see that the alert contained the id of the clicked element, so I’ll use that to determine which button was clicked. Below is the modified doNav function that keys in on the id’s of our buttons:

    ns.doNav = function(e){
	if (e.target.id === 'btnleft'){
	    // move the sideshow to the left
	} else {
	    // move the slideshow to the right
	}
    };

The next thing we need is a way of advancing the slideshow in one direction or another. iScroll provides a method for this purpose called next() to advance the slideshow forward and prev() to advance the slideshow to a previous slide. There is also goToPage() but I’ll stick with the previous two methods – you can of course opt to use the later method to take advantage of the easing property that it exposes.

This is all we need to get the navigation buttons working. See the code below followed by the working example.

    ns.doNav = function(e){
	if (e.target.id === 'btnleft'){
	    iscroll.prev(); // scroll left
	} else {
	    iscroll.next(); // scroll right
	}
    };

Dimming the navigation buttons

One thing that you might think is missing is disabling the buttons in some way to reflect that you are either at the beginning or end of the slideshow. By digging into the iScroll object we can find some properties that will make it easy for us to do this.

First we will need to know what the current slide number is. That information is held in the iScroll object that can be referenced via our private _iscroll variable. Log your iScroll object to the console and note the currentPage property. Expand it and you will see the following:

currentPage:{
    pageX:0, // this holds the slide number for horizontal iScrolls
    pageY:0, // this holds the slide number for vertical iScrolls
    x:-0,
    y:0
}

As you can see the pageX property holds the slide number for horizontal scrollers. Given that fact we would access the current slide number by doing this:

var slideNumber = _iscroll.currentPage.pageX;

Next we need to know how many slides there are. Of course we know that there are 4 but iScroll also holds this for us in the iScroll object’s pages property. Lets save it for later use:

var slideLength = _iscroll.pages.length;

Below is a function that dims the navigation buttons when they are no longer usable due to the slideshow being either at the beginning or end of the slide list (if you are using jQuery you will want to add or remove css classes to the elements instead of the in-line editing that I’m doing):

    // show or dim the navigation buttons
    function _hideShowNavButtons(e){
	var slideNumber = _iscroll.currentPage.pageX;
	var slideLength = _iscroll.pages.length - 1;
	// show or hide the next and previous buttons according to where we are in the slideshow
	document.getElementById('btnleft').style.opacity = slideNumber === 0 ? .3 : 1;
	document.getElementById('btnright').style.opacity = slideNumber === slideLength ? .3 : 1;
    }

To make the above work we need to fire it when the slideshow has stopped scrolling – thus we’ll hook into iScroll’s scrollEnd event. We’ll do this within the init() function which has been modified below:

    // init the app
    ns.init = function(){
	_iscroll = new IScroll('#slideshow',{
	    scrollX: true,
	    snap:'li',
	    momentum:false
	});
		
	// add scrollend event to iscroll
	_iscroll.on('scrollEnd',_hideShowNavButtons); // NEW LINE!! dim or show the buttons on "scrollEnd"
		
	// add event listeners
	if (window.addEventListener){
	    document.getElementById('slideshow_wrapper').addEventListener('click',ns.doNav,false);
	} else {
	    window.attachEvent('onload',slideshow.init); //IE
	}
    };

Lastly, we need to code the “Previous” button so that it is dimmed to begin with. I hardcode that into the init() function via this line (as before use jQuery or your favorite library instead as needed):

// set the default state for the left/previous button
document.getElementById('btnleft').style.opacity = .3;

Here is the result:

We’re done! You could of course add a lot more features such as notes or slide numbering, etc. Right-click and inspect the iFrame holding the final example above or see the complete source printed out below.

<!DOCTYPE html>
<html><head><title></title>

<style type="text/css">
    li {
	list-style-type: none;
	margin: 0px;
	padding: 0px;
	float:left;
    }
	
    ul {
	position: relative;
	height: 177px;
	width: 1136px;
	margin: 0px;
	padding:0px;
    }
	
    #slideshow{
	position: relative;
	height: 177px;
	width: 284px;
	overflow: hidden;
    }
    #btnleft, #btnright {
	position:absolute;
	top: 70px;
	height: 40px;
	width: 36px;
	z-index: 100;
	background-size:contain;
    }
    #btnleft{
	background-image: url(images/slideshow_left_arrow.png);
	left: 8px;
    }
    #btnright{
	background-image: url(images/slideshow_right_arrow.png);
	left: 255px;
    }
</style>

<script type="text/javascript" src="js/iscroll.js"></script>
<script type="text/javascript">
;(function(ns){
    // hold a reference to the iScroll object
    var _iscroll = null;
	
    // init the app
    ns.init = function(){
	_iscroll = new IScroll('#slideshow',{
	    scrollX: true,
	    snap:'li',
	    momentum:false
        });
		
        // add scrollend event to iscroll
        _iscroll.on('scrollEnd',_hideShowNavButtons);
		
	// set the default state for the left/previous button
	document.getElementById('btnleft').style.opacity = .3;
		
	// add event listeners
	if (window.addEventListener){
	    document.getElementById('slideshow_wrapper').addEventListener('click',ns.doNav,false);
	} else {
	    window.attachEvent('onload',slideshow.init); //IE
	}
    };
	
    // handle navigation button clicks
    ns.doNav = function(e){
	if (e.target.id === 'btnleft'){
	    _iscroll.prev(); // scroll left
	} else {
	    _iscroll.next(); // scroll right
	}
    };
	
    // show or hide the navigation buttons
    function _hideShowNavButtons(e){
	var slideNumber = _iscroll.currentPage.pageX;
	var slideLength = _iscroll.pages.length - 1;
	// show or hide the next and previous buttons according to where we are in the slideshow
	document.getElementById('btnleft').style.opacity = slideNumber === 0 ? .3 : 1;
	document.getElementById('btnright').style.opacity = slideNumber === slideLength ? .3 : 1;
    }
	
})(this.slideshow = {});

;(function(){
    if (window.addEventListener){
	window.addEventListener('load',slideshow.init,false);
    } else {
	window.attachEvent('onload',slideshow.init); //IE
    }
})();
</script>
</head>
<body>
    <div id="slideshow_wrapper">
	<div id="slideshow">
	    <ul>
		<li><img src="images/image_1.jpg" height="177" width="284" /></li>
		<li><img src="images/image_2.jpg" height="177" width="284" /></li>
		<li><img src="images/image_3.jpg" height="177" width="284" /></li>
		<li><img src="images/image_4.jpg" height="177" width="284" /></li>
	    </ul>
	</div>
	<div id="btnleft"></div>
	<div id="btnright"></div>
    </div>
</body>
</html>

Passing Objects without Reference

30 Apr 2015

Here’s a little thing that I do to prevent passing object references when I really just want a copy of the object itself (a deep copy). This is super simple – much simpler than enumerating an object in order to reveal/copy its properties and values into a new object.

Here is an example of a closure that has a private variable called _data. There is a getter function called getData() that is meant to return the value of _data.

;(function(ns){

    var _data = {title:'test data'};
    
    ns.getData = function(){
        return _data;
    }

})(this.test = this.test || {});

Pasting the above in Chrome’s console you can see what happens when I create the variable dog to receive _data. I attempt to change the value of dog.title and see that it changes but when I view _data via the getter function I find that _data has changed even though it is encapsulated within the “test” namespace.

obj_by_ref_01

JavaScript passes objects around by reference, not by value, so what happened above is not a surprise. In layman’s terms dog maintains a reference back to the object _data which means that dog.title is in reality _data.title. Therefore modifying one is really modifying the other. Our intent is to pass the object as if it were a value without any reference back to where it came from.

What I need then is a way to break the reference chain so that I can receive the desired object as a “value” (kind of) instead of as a reference. I do that by stringifying the object into JSON and then parsing the JSON back into an object. As soon as the object is translated into JSON the reference no longer exists. Converting it back to an object via JSON.parse() gives me the desired “reference-free” deep copy of _data.

Here’s the same code with the JSON methods added:

;(function(ns){

    var _data = {title:'test data'};
    
    ns.getData = function(){
        return JSON.parse(JSON.stringify(_data));
    }

})(this.test = this.test || {});

And doing the exact same thing in Chrome’s console reveals that _data is untouched whenever dog.title is changed.

obj_by_ref_02