Skip to content

Instantly share code, notes, and snippets.

@sparksm
Created April 19, 2013 15:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sparksm/5421166 to your computer and use it in GitHub Desktop.
Save sparksm/5421166 to your computer and use it in GitHub Desktop.

overview

So you want to make a slideshow on your blog. First you'll need content. Your content can come from anywhere. JSON, XML, and HTML are supported. So get that setup and ready to go. Once you have that, put jQuery, jquery.knot.js, and knot.base.css on your page. Add the initialization block and you've got a slideshow. Want to add features? Just change the settings in the init block. Don't like the way it looks? Add some css to your page. Hide stuff you don't like. Change the colors etc. It really is that simple.

quickstart

  1. Add the js to your page. http://o.aolcdn.com/os/aol/knot/v2/jquery.knot.min.js
  2. Add the base css to your page. http://o.aolcdn.com/os/aol/knot/css/knot.base.css
  3. Add configuration and initialization javascript.

knot plugins

$.fn.knot

This is the core plugin for used for initializing data acquisition and mapping. It is also used to initialize user interfaces by default.

Let's start off with a simple example.

####The HTML (abridged)

<ul class="photo-gallery">
  <li class="photo" data-type="photo" data-media-id="5422878">
		<h4>2014 Audi R8 V10 Plus rear 3/4 view</h4>
		<a href="/photos/2014-audi-r8-v10-plus-first-drive/5422878/" data-photo-src="http://www.blogcdn.com/www.autoblog.com/media/2012/11/04-2014-audi-r8-v10-plus-fd.jpg">2014 Audi R8 V10 Plus</a>
	</li>
	<li class="photo" data-type="photo" data-media-id="5422879">
		<h4>2014 Audi R8 V10 Plus side view</h4>
		<a href="/photos/2014-audi-r8-v10-plus-first-drive/5422879/" data-photo-src="http://www.blogcdn.com/www.autoblog.com/media/2012/11/05-2014-audi-r8-v10-plus-fd.jpg">2014 Audi R8 V10 Plus</a>
	</li>
</ul>

####The JavaScript

var $knot = $('#knot');

var knotSettings = {
	data: '.photo-gallery',
	contentMap: {
		entryArray: {
			path: 'li.photo'
		},
		'photo_src': {
			path: 'a[data-photo-src]'
		},
		caption: {
			path: 'a[text]'
		},
		title: {
			path: 'h4[text]'
		},
		thumbnail: {
			path: 'a[data-photo-src]'
		},
		type: {
			path: '[data-type]'
		}
	}
};

$knot.knot(knotSettings);

Now, the code above will render a simple slider with the title and captions below.

####data (required) The data option defines what data to use to build the gallery. This object should include the array of entries that will become slides. data can be set as a css selector string, a json object, or a url to a json or xml endpoint.

####contentMap (required) The contentMap option is an associative array that will define where to select the data to use to render the gallery.

####entryArray (required) The entryArray option is a selector or dot syntax string used to select, within the context of data, an array of objects to use as each slide.


The rest of the options within the the contentMap are arbitrary with a few exceptions. First I'll explain the exceptions. I'll go into the reasoning for arbitrary keys a bit later.

There are certian fields required for each type of slide that you wish to render. List of types:

Slide Type Required Keys
photo photo_src
image photo_src
video player
audio player
quote quoteSource, text
tweet tweet_link
text title, body
html html
embed embed
ad magicNumber

Additonal Options

Here is a list of available options and what they do.

Option Key Value Type(s) Possible Values Behavior Default Notes
activeSlide number number The gallery will change to this index when it renders 0
after string, function html string, function returning html string, null This html string will be inserted into the dom after the target element null
before string, function html string, function returning html string, null This html string will be inserted into the dom before the target element null
bottomExtraHtml string, function html string, function returning html string, null This html string will be inserted into the bottom section of the fullscreen view null
build boolean boolean Tells the init plugin to render the ui true
contentMap object object Used to map data to properties for rendering {} required
data string, object url, css selector, json object Used to acquire the slideshow's data '' required
dataType string xml, json, jsonp, html Used to define the type of data to be acquired jsonp can dynamically detect html
defaultType string see list of types above Sets entries to this type when type is not available photo
downloadEnabled boolean boolean Covers the slide with an img element that can be used to download the slide's image false loads image only onContextMenu or press and hold events
effect string translate, fade, none Sets the type of transition that will occur between slides translate
fullscreenAdMN number number, null The magic number used to get the 300x250 in the fullscreen right rail null
fullscreenHtml string, function html string, function returning html string, null Overwrites the html used to render the fullscreen view null
fullscreenLBMN number number, null The magic number used to get the 728x90 for the upper area in the fullscreen view null
fullscreenRefreshDivId array array of id strings, null Sets which elements to target for ad refresh in fullscreen view 'knotFullscreenAd-' + options.galleryId
fullscreenThumbs boolean boolean Toggles thumbnails in the fullscreen view false
fullscreenThumbnailControls boolean boolean Inserts arrows to paginate fullscreen thumbnails false Is ignored unless fullscreenThumbnailStyle is set to carousel
fullscreenThumbnailPosition string slider, null Initiallizes thumbnails in either the right rail or below the slider null
fullscreenThumbnailStyle string normal, carousel Sets the display of the thumbs as either a grid or a carousel normal
galleryId number, string number, string, null Is used to create ad spot id's for ad refresh targeting null
hideData boolean boolean Tells the init to hide the data source if it is an html element true
isInternational boolean boolean Used for omnitureConfig page tracking false
refreshCount number number Sets the refresh rate for ads 4
refreshDivId array array of id strings, null Sets which elements to target for ad refresh null
rightRailHtml string, function html string, function returning html string, null Overwrites the html used to render the right rail above the 300x250 ad fullscreen view null
slideshowTitle string string, null Used to render the slideshow's title in several places of the ui's null
thumbHeight number number Set the thumbnail height 80
thumbnails boolean boolean Toggles the render of thumbnails in the default view false
thumbnailControls boolean boolean Inserts arrows to paginate thumbnails false Is ignored unless thumbnailStyle is set to carousel
thumbnailsOnly boolean boolean Prevents the slider from rendering and only renders the thumbnails false Does not prevent fullscreen from rendering
thumbnailPosition string afterCaption, '', null Sets the placement of the thumbnails to either before the caption and title or after null
thumbnailStyle string normal, carousel Sets the display of the thumbs as either a grid or a carousel normal
thumbWidth number number Set the thumbnail width 80
trackingId string string, null Used to set omnitureConfig objects channel property null
transitionSpeed number number Time in milliseconds the transition between slides should take 600

Callbacks

Here is a list of callbacks to which we can hook functions

Callback Execution Point
onNextSlide Next slide requested
onPrevSlide Previous slide requested
onSlideChange Slide change triggered
onSlideChangeComplete Slide changed
onSlideLoad Slide is loaded/preloaded
onThumbClick Thumbnail is clicked
onEnterFullscreen Fullscreen was entered
onExitFullscreen Fullscreen was exited
onUiBuilt Ui or Fullscreen Ui was inserted to DOM
onKnotInit Data aquired, mapped, and stored on target

Advanced Options

Now that we've gone over the basics of getting a gallery up and running, let's go over some more advanced features.

Each key that you set within the contentMap, with some exceptions, has two options path and override. entryArray, and thumbnail have the addition html option.

####path (required but can be '') This is the dot syntax or css selector used to lookup values from the data object.

####override This allows a string or function that will be used to force the value to something else. For example, if your data doesn't specify a type for each slide but you know it will always be a photo, like an Instagram feed, you can force all slide to use a type of photo.

type: {
	path: '',
	override: 'photo'
}

Or say you want to use a number formatted as a dollar amount:

cost: {
	path: '',
	override: (function () {
		var cost = 123122
		return '$' + cost.toFixed(2);
	}())
}

####html This option must be a function that takes a single argument that is the data for that slide and must return a jQuery object. This is where some neat stuff happens. The data object that gets passed to this function contains the properties that you have arbitrarily set in the contentMap option. Here you can define any slide appearance that you wish. For example, say we wanted to show a set of photos where we credit the photo with semi-transparent overlay with a link to the owner's website. We might build something like this:

contentMap: {
	entryArray: {
		path: 'li.photo',
		html: function (entry) {
			return $([
				'<div style="position:relative">'
					'<div style="background-image:url("', entry.photo_src, '");position:absolute;top:0;right:0;bottom:0;left:0;"></div>',
					'<div style="background:rgba(0,0,0,.3);position:absolute;bottom:0;right:0">',
						entry.credit, ': <a href="', entry.credit_url, '" target="_blank">', entry.user, '</a>',
					'</div>',
				'</div>'
			].join(''));
		}
	},
	'photo_src': {
		path: 'a[data-photo-src]'
	},
	credit: {
		path: '[data-credit]'
	},
	credit_user: {
		path: '[data-username]'
	},
	credit_url: {
		path: '[data-user-profile]'
	},
	caption: {
		path: 'a[text]'
	},
	title: {
		path: 'h4[text]'
	},
	type: {
		path: '',
		override: 'photo'
	}
}

In this example we have set type to photo because we want to prefetch the image before triggering the loaded callback. By default slide types of image and photo are the only types that do prefecthing before transitioning to the slide. Just as before type photo requires the photo_src definition.

Data, Events, Options, and Extending

Here I will go over the different ways to interact with the api's and data made available by the different plugins. I will also go over the ways you can set options and extend the plugins.

Data

First, all methods that are available through the API are accessed in the same way after initialization. This is true for all plugins as well.

$('#knot').knot('methodName', [arguments]);

In the case of the other plugins you would use the coresponding plugin namespace.

$('#knot').knotUi('methodName', [arguments]);
$('#knot').knotFullscreen('methodName', [arguments]);
$('#knot').knotThumbs('methodName', [arguments]);

Next, you can access the data for any and all plugin instances with jQuery's $.fn.data() function. Each instance stores itself as data on the target element.

$('#knot').data('knot');
$('#knot').data('knotUi');
$('#knot').data('knotFullscreen');
$('#knot').data('knotThumbs');

Events

Now, almost everything that happens in the UIs are trigger by jQuery events via $.fn.trigger with $.fn.delegate and $.fn.bind (didn't use $.fn.on for backwards compat). Here are some events that get trigger on the element on which the knot plugin was initialized.

From the core:

Event Arguments
knotReady event, context
knotDestroyed event

From the UI:

Event Arguments
knotUiBuilt event
showNextSlide event
showPrevSlide event
slideChangeStart event, index, direction
slideChange event, index, direction
slideChangeComplete event, index

From the fullscreen UI:

Event Arguments
knotFullscreenDestroyed event
knotFullscreenUiBuilt event
enterFullscreen event
enteredFullscreen event, index
exitFullscreen event, index
exitedFullscreen event, index
knotResize event

From the thumbnails:

Event Arguments
knotThumbsDestroyed event
thumbsAvailable event
thumbMouseEnter event, original event, index
thumbsCentered event

You can bind, delegate or on to any of these events on the element on which the plugin was initialized.

Options

Options are typically set by the initialization block but can be set or changed after initilization using the option method available for each plugin.

$('#knot').knotUi('option', {fullscreen: false});

To get the current value of an option use .data()

$('#knot').data('knot').options.fullscreen

Extending

"Extending" is kind of a broad term. What I mean by extending is adding plugins to the stack, adding methods to the plugins, adding renders to the renderer list, and simple inheretance of the prototypes for a plugin. You might think, "that sounds complicated.", and you'd be right. So I'll try to make it easy.

adding plugins to the stack

I recommend that you follow this pattern when adding plugins to the knot stack.

//the constructor
$.newPlugin = function (context, element) {
	this.$element = $(element);
	
	this._context(context);
	this._init();
};

//default settings
$.newPlugin.settings = {
	name: 'myPlugin'
};

//the prototype
$.newPlugin.prototype = {
	_context: function (context) {
		if (context.options) {
			this.options = context.options;
		}
		this.context = context;
	},
	init: function () {
		//some other methods
	},
	destroy: function () {
		this.$element
			.removeData('myPlugin')
			.unbind('.myPlugin')
			.undelegate('.myPlugin')
			.empty();
	}
}

//the plugin
$.fn.newPlugin = function (options,=) {
	if (typeof options === 'string') {
		var args = Array.prototype.slice.call(arguments, 1);
		this.each(function () {
			var instance = $.data(this, 'newPlugin');
			if (!instance) {
				return;
			}
			if (!$.isFunction(instance[options]) || options.charAt(0) === "_") {
				return;
			}
			instance[options].apply(instance, args, temp);
		});
	} else {
		this.each(function () {
			var instance = $.data(this, 'newPlugin');
			if (instance) {
				instance.destroy();
			}
			$.data(this, 'newPlugin', new $.newPlugin(options, this));
		});
	}
	return this;
};

adding methods to the plugins

I've included in the plugins extend methods that allow you to add or overwrite methods for the plugin.

$('#knot').knot('extend', 'newMethod', function () {
	var _this = this;
	//this reffers to the plugin instance's prototype
	//your new method
	
	//i like to return this so that methods can be chained elsewhere in the prototype.
	return this;
});

adding renders to the renderer list

This is how you would add a new renderer type to the renderer plugin.

$.knotRender('add', 'phonebook', function ($slide, callback) {
	$slide.html('<div class="your-renderer-html">' + $slide.data('index') + '</div>');
	if (callback) {
		callback($slide);
	}
});

It's important to know that you MUST have a callback that passes $slide as the only argument. The $slide argument that the renderer receives is the jQuery collection that contains the slide's li that will transition into view when active.

simple inheretance of the prototypes for a plugin

So let's say you want to create a plugin that shares all of the same methods as another plugin except you want to overwrite a couple of methods and add a few without fucking up the original plugin. It's what the fullscreen plugin does to the ui plugin. Here's how you might do that.

//javascript constructor extender
var __extends = function (d, b) {
	function A() {
		this.constructor = d;
	}
	A.prototype = b.prototype;
	d.prototype = new A();
};

//extends ui. classy.
$.newUiBasedPlugin = function (context, $el) {
	$.knotUi.call(this, context, $el);
};
__extends($.newUiBasedPlugin, $.knotUi);

var methods = {
	//your methods
};

$.each(methods, function (name, method) {
	$.newUiBasedPlugin.prototype[name] = method;
});

//the plugin
$.fn.newUiBasedPlugin = function (options,=) {
	if (typeof options === 'string') {
		var args = Array.prototype.slice.call(arguments, 1);
		this.each(function () {
			var instance = $.data(this, 'newUiBasedPlugin');
			if (!instance) {
				return;
			}
			if (!$.isFunction(instance[options]) || options.charAt(0) === "_") {
				return;
			}
			instance[options].apply(instance, args, temp);
		});
	} else {
		this.each(function () {
			var instance = $.data(this, 'newUiBasedPlugin');
			if (instance) {
				instance.destroy();
			}
			$.data(this, 'newUiBasedPlugin', new $.newUiBasedPlugin(options, this));
		});
	}
	return this;
};

knot utilities

$.knotData({source, type, callback[data, type]});

This utility is used to fetch data from a defined source.

The source can be a url or a css selector. If the source is a url, the plugin will asynchronously retrieve the data before it executes the callback. If the source is a css selector the data returned will be the jQuery object created from that selector. The type can be set to json, jsonp, xml, or html. The type argument defaults to jsonp and will automaticly detect jsonp or html. The callback receives two arguments - the resulting data and the type. Once the data has been returned the callback will execute.

$.knotData({
	source: 'http://www.example.com/data.json',
	type: 'json',
	callback: function (data, type) {
		//do something
	}
});

$.knotLookup(data, map);

This utility is used to return data described by a selector from an object.

The data argument can be either a native JavaScript object or a jQuery object. The map argument is either a dot syntax string or a css selector string. Dot syntax is used to select values from native objects. CSS selectors are used to select values from jQuery ojects.

Examples:

Using dot syntax.

var lookedUp = $.knotLookup({foo: {bar: 1}}, 'foo.bar');

lookedUp will return 1.

When using dot syntax accessing array is accomplished by using the index of the array you want to search. object.array.0.value

Using html and css selectors.

<div id="#data-element">
	<a href="http://www.example.com">Example</a>
</div>
var lookedUp = $.knotLookup('#data-element', 'ul li a[href]');

lookedUp will return http://www.example.com.

When using css selectors, if you want to return the attribute of an element simply select the attribute without passing a value. .list li a[href] If you want to return the text or innerHtml use [text] and [html] respectively.

$.knotRender(type, data, callback)

This utility is used transform the data for a slide into the final slide to be rendered.

$.knotRender('photo', {
	'photo_src': 'http://www.example.com'
}, function ($slide) {
	$slide.addClass('loaded');
});

$.xml2json(xml);

Takes your xml and converts it to json. Primarily used for when the $.knotData function needs to get xml.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment