registering deferred methods with callback argument, fixes #30

This commit is contained in:
Tomas Sardyha
2012-09-10 22:00:40 +02:00
parent 26e74abf07
commit c7634aa6a4
5 changed files with 212 additions and 135 deletions

View File

@@ -4,32 +4,90 @@ http://desandro.github.com/imagesloaded/
A jQuery plugin that triggers a callback after all the selected/child images have been loaded. Because you can't do `.load()` on cached images.
## Basic usage
## Calling
```js
$('#my-container').imagesLoaded( function( $images, $proper, $broken ) {
// callback provides three arguments:
// $images: the jQuery object with all images
// $proper: the jQuery object with properly loaded images
// $broken: the jQuery object with broken images
// `this` is a jQuery object of container
console.log( $images.length + ' images total have been loaded in ' + this );
console.log( $proper.length + ' properly loaded images' );
console.log( $broken.length + ' broken images' );
$(selector).imagesLoaded( [ callback ] );
```
### selector
ImagesLoaded can be called on an elements with images within them, images directly, or a combination of both.
###### *Example*
```js
// Calling on an element that may contain images
$('#content').imagesLoaded(fn);
// Calling on image elements directly
$('img').imagesLoaded(fn);
// Combination of both
$('#content, #gallery > img').imagesLoaded(fn);
```
### [ callback ]
Callback argument can be a function, or an object map with deferred methods.
#### callback:function
Pass a function to be called when all images has finished with loading. This is the simplest way how to use imagesLoaded.
##### *this*
When executed, the callback function scope (`this`) is a jQuery object with element or set of elements on which the imagesLoaded has been called (`$(selector)`).
##### arguments
Callback function receives 3 arguments:
+ **$images:** `Object` jQuery object with all images
+ **$proper:** `Object` jQuery object with properly loaded images
+ **$broken:** `Object` jQuery object with broken images
###### *Example*
```js
$('#my-container, .article img').imagesLoaded( function( $images, $proper, $broken ) {
console.log( $images.length + ' images total have been loaded' );
console.log( $proper.length + ' properly loaded images' );
console.log( $broken.length + ' broken images' );
});
```
You can call `imagesLoaded` on a set of images as well.
#### callback:object
To bind deferred methods before the determination process starts, pass an object with map of given method callbacks instead of a callback function.
You can read more about these methods and their behavior in [Deferred section](#deferred) below.
###### *Example*
```js
$('.article img').imagesLoaded( myFunction );
$(selector).imagesLoaded({
done: function ($images) {},
fail: function ($images, $proper, $broken) {},
always: function () {},
progress: function (isBroken, $images, $proper, $broken) {}
});
```
If you are passing object with deferred methods, but you still want to use the simple callback functionality, use the `callback` property, like so:
```js
$(selector).imagesLoaded({
// ... deferred methods ...
callback: function ($images, $proper, $broken) {}
});
```
## Deferred
As of v1.2.0, `imagesLoaded` returns jQuery deferred object.
### Behaviour
**Resolved**: deferred is *resolved* when all images have been properly loaded
@@ -40,57 +98,70 @@ As of v1.2.0, `imagesLoaded` returns jQuery deferred object.
### Usage
```js
var dfd = $('#my-container').imagesLoaded(); // save a deferred object
// Save a deferred object with postponed determination process
var dfd = $('#my-container').imagesLoaded();
// Always
dfd.always( function(){
console.log( 'all images has finished with loading, do some stuff...' );
console.log( 'all images has finished with loading, do some stuff...' );
});
// Resolved
dfd.done( function( $images ){
// callback provides one argument:
// $images: the jQuery object with all images
console.log( 'deferred is resolved with ' + $images.length + ' properly loaded images' );
// callback provides one argument:
// $images: the jQuery object with all images
console.log( 'deferred is resolved with ' + $images.length + ' properly loaded images' );
});
// Rejected
dfd.fail( function( $images, $proper, $broken ){
// callback provides three arguments:
// $images: the jQuery object with all images
// $proper: the jQuery object with properly loaded images
// $broken: the jQuery object with broken images
console.log( 'deferred is rejected with ' + $broken.length + ' out of ' + $images.length + ' images broken' );
// callback provides three arguments:
// $images: the jQuery object with all images
// $proper: the jQuery object with properly loaded images
// $broken: the jQuery object with broken images
console.log( 'deferred is rejected with ' + $broken.length + ' out of ' + $images.length + ' images broken' );
});
// Notified
dfd.progress( function( isBroken, $images, $proper, $broken ){
// function scope (this) is a jQuery object with image that has just finished loading
// callback provides four arguments:
// isBroken: boolean value of whether the loaded image (this) is broken
// $images: jQuery object with all images in set
// $proper: jQuery object with properly loaded images so far
// $broken: jQuery object with broken images so far
console.log( 'Loading progress: ' + ( $proper.length + $broken.length ) + ' out of ' + $images.length );
// function scope (this) is a jQuery object with image that has just finished loading
// callback provides four arguments:
// isBroken: boolean value of whether the loaded image (this) is broken
// $images: jQuery object with all images in set
// $proper: jQuery object with properly loaded images so far
// $broken: jQuery object with broken images so far
console.log( 'Loading progress: ' + ( $proper.length + $broken.length ) + ' out of ' + $images.length );
});
```
**Important!**: progress method should be always registered with `callback:object` argument, which ensures that it will be registered before the determination process starts.
Otherwise you might run into an issue where by the time you register the progress method all images have been loaded, and there is nothing to report anymore.
### Requirements
Deferred is being used only when present, so having older versions of jQuery doesn't break the plugin, just removes the functionality.
For using any Deferred method, you need jQuery **v1.5** and higher.
For using Deferred progress method, you need jQuery **v1.7** and higher.
For availability of other Deferred methods, read the [jQuery Deferred object documentation](http://api.jquery.com/category/deferred-object/).
+ Deferred is being used only when present, so having older versions of jQuery doesn't break the plugin, just removes the functionality.
+ For using any Deferred method, you need jQuery **v1.5** and higher.
+ For using Deferred progress method, you need jQuery **v1.7** and higher.
+ For availability of other Deferred methods, read the [jQuery Deferred object documentation](http://api.jquery.com/category/deferred-object/).
## Behavior notes
### Determination process
Every browser is handling image elements differently. We are trying to check for state in image attributes when possible & reliable, but in some browsers (especially older ones)
we have to reset `img.src` attribute to re-trigger load/error events. That is the only possible way how to check for an image status,
as well as differentiate between proper and broken images. We are resetting the src with blank image data-uri to bypass webkit log warning (thx doug jones).
Fortunately, since v2.0.0 we are in a state where imagesLoaded is both cross-browser reliable and fast, with only a few minor [known issues](#known-issues).
### Caching
The state of all once checked images is cached, so the calls repeated on the same images don't have to go through a determining process for each image again.
The state of all once checked images is cached, so the calls repeated on the same images don't have to go through a determination process for each image again.
Determining might be slow in older browsers in which we have to reset `src`, and also might introduce image flickering.
Image state is stored in `$.data` associated to that particular image DOM element. That means that everything is stored per page load,
so you don't have to worry that temporarily unavailable images will be considered as broken on a next page load as well. This is just for a multiple calls within one page load.
Image state is stored in `$.data` associated to that particular image DOM element and its `src` path (changing `src` of an image resets its cache).
That means that everything is stored per page load, so you don't have to worry that temporarily unavailable images will be considered as broken on a next page load as well.
Caching is just for a multiple calls within one page load.
If, however, you need it from some reason, you can remove this data from an image with:
@@ -98,18 +169,11 @@ If, however, you need it from some reason, you can remove this data from an imag
$.removeData( img, 'imagesLoaded' );
```
### Image flickering
In IE (particularly in older versions) you might see images flicker as plugin has to refresh all `src` attributes to catch event types. That is the only known
way how to check for loading status of both proper and broken images in IE browsers, as these dinosaurs don't bother changing any image property once an image has
been recognized as broken. The only thing they do is send an `error` event. Without refreshing `src` and catching it, it would be impossible to differentiate
between broken images and proper images that are still loading.
Thankfully, this flickering is invisible most of the time.
## Known issues
+ unreliable differentiation between proper and broken images in Opera versions lower than 11 (market share ~0.1%), but callback still fires
+ Unreliable differentiation between proper and broken images in Opera versions lower than 11 (market share ~0.1%), but callback still fires.
+ In IE (particularly in older versions) you might see images flicker as plugin has to refresh all `src` attributes to catch event types.
Thankfully, this flickering is invisible most of the time.
## Contribute
@@ -120,4 +184,3 @@ It ain't easy knowing when images have loaded. [Every browser has its own little
+ [**View contributors**](https://github.com/desandro/imagesloaded/contributors)
+ [ajp](http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f)
+ Oren Solomianik

View File

@@ -69,17 +69,17 @@
<pre><code class="language-javascript">
// Call imagesLoaded and position images
holder.imagesLoaded(function( $images, $proper, $broken ){
$holder.imagesLoaded(function( $images, $proper, $broken ){
var $container = this,
x = 1;
var $container = this,
x = 1;
$images.each( function() {
var $this = $(this).css({ left: x });
x += $this.width() + 1;
});
$images.each( function() {
var $this = $(this).css({ left: x });
x += $this.width() + 1;
});
$container.width(x);
$container.width(x);
});
</code></pre>
@@ -143,37 +143,40 @@ holder.imagesLoaded(function( $images, $proper, $broken ){
<h2>Code</h2>
<pre><code class="language-javascript">
// Call imagesLoaded with callback and save the deferred object
var dfd = $("#holder").imagesLoaded(function( $images, $proper, $broken ){
// Call imagesLoaded with multiple callbacks, and save the deferred object
var dfd = $holder.imagesLoaded({
callback: function($images, $proper, $broken){
totalLabel.text( $images.length );
properLabel.text( $proper.length );
brokenLabel.text( $broken.length );
$totalLabel.text( $images.length );
$properLabel.text( $proper.length );
$brokenLabel.text( $broken.length );
});
},
progress: function (isBroken, $images, $proper, $broken) {
// Deferred magic
dfd.progress(function( isBroken, $images, $proper, $broken ){
var loadingSpan = this.siblings('.loading');
var loadingSpan = this.siblings('.loading');
if( isBroken ){
loadingSpan.removeClass('loading').addClass('broken');
} else {
loadingSpan.fadeOut(200, function(){ $(this).remove(); });
}
if( isBroken ){
loadingSpan.removeClass('loading').addClass('broken')
} else {
loadingSpan.fadeOut(200, function(){ $(this).remove(); });
}
$progressBar.css({ width: Math.round( ( ( $proper.length + $broken.length ) * 100 ) / $images.length ) + '%' });
progressBar.css({ width: Math.round( ( ( $proper.length + $broken.length ) * 100 ) / $images.length ) + '%' });
}
});
}).always(function(){
// Subsequent deferred method registration (not to be used with progress method)
dfd.always(function(){
var dfdState = dfd.state();
var dfdState = dfd.state();
dfdLabel.addClass( 'label-' + ( dfdState === 'resolved' ? 'success' : 'important' ) ).text( dfdState );
$dfdLabel.addClass( 'label-' + ( dfdState === 'resolved' ? 'success' : 'important' ) ).text( dfdState );
progress.hide();
statusBar.show();
progressBar.css({ width: 0 });
$progress.hide();
$statusBar.show();
$progressBar.css({ width: 0 });
});
</code></pre>

View File

@@ -1,5 +1,5 @@
/*!
* jQuery imagesLoaded plugin v2.0.1
* jQuery imagesLoaded plugin v2.1.0
* http://github.com/desandro/imagesloaded
*
* MIT License. by Paul Irish et al.
@@ -23,6 +23,17 @@ $.fn.imagesLoaded = function( callback ) {
proper = [],
broken = [];
// Register deferred callbacks
if ($.isPlainObject(callback)) {
$.each(callback, function (key, value) {
if (key === 'callback') {
callback = value;
} else if (deferred) {
deferred[key](value);
}
});
}
function doneLoading() {
var $proper = $(proper),
$broken = $(broken);

View File

@@ -7,14 +7,14 @@ jQuery(function($){
(function(){
// Variables
var simple = $('#simple'),
holder = simple.find('.holder'),
controlbar = simple.find('.controlbar');
var $simple = $('#simple'),
$holder = $simple.find('.holder'),
$controlbar = $simple.find('.controlbar');
function runTest( holder ){
function runTest( $holder ){
// Call imagesLoaded and position images
holder.imagesLoaded(function( $images, $proper, $broken ){
$holder.imagesLoaded(function( $images, $proper, $broken ){
var $container = this,
x = 1;
@@ -31,7 +31,7 @@ jQuery(function($){
}
// Controls
controlbar.find('[data-action]').click(function(){
$controlbar.find('[data-action]').click(function(){
var el = $(this),
action = el.data('action');
@@ -40,7 +40,7 @@ jQuery(function($){
case 'run':
//Empty holder and apped images
holder.empty().append(
$holder.empty().append(
'<img src="img/img1.jpg" alt="Lorempixel">' +
'<img src="img/img2.jpg" alt="Lorempixel">' +
'<img src="img/img3.jpg" alt="Lorempixel">' +
@@ -48,15 +48,15 @@ jQuery(function($){
'<img src="img/img5.jpg" alt="Lorempixel">' +
'<img src="img/img6.jpg" alt="Lorempixel">'
);
runTest( holder );
runTest( $holder );
break;
case 'empty':
holder.empty().width('auto');
$holder.empty().width('auto');
break;
case 'clone':
var clone = holder.clone().addClass('clone').append('<span class="remove"/>').insertAfter( holder );
var clone = $holder.clone().addClass('clone').append('<span class="remove"/>').insertAfter( $holder );
runTest( clone );
break;
@@ -65,7 +65,7 @@ jQuery(function($){
});
// Click-delete holders
simple.on('click', '.clone', function(){
$simple.on('click', '.clone', function(){
$(this).fadeOut( 200, function(){
@@ -85,16 +85,16 @@ jQuery(function($){
(function(){
// Variables
var advanced = $('#advanced'),
holder = advanced.find('.holder'),
statusBar = advanced.find('.status'),
totalLabel = statusBar.find('.totalcount'),
properLabel = statusBar.find('.propercount'),
brokenLabel = statusBar.find('.brokencount'),
dfdLabel = statusBar.find('.dfdstatus'),
progress = advanced.find('.progress'),
progressBar = progress.find('.bar'),
controlbar = advanced.find('.controlbar'),
var $advanced = $('#advanced'),
$holder = $advanced.find('.holder'),
$statusBar = $advanced.find('.status'),
$totalLabel = $statusBar.find('.totalcount'),
$properLabel = $statusBar.find('.propercount'),
$brokenLabel = $statusBar.find('.brokencount'),
$dfdLabel = $statusBar.find('.dfdstatus'),
$progress = $advanced.find('.progress'),
$progressBar = $progress.find('.bar'),
$controlbar = $advanced.find('.controlbar'),
broken_urls = [
'missing.jpg',
'absent.png',
@@ -109,49 +109,49 @@ jQuery(function($){
function checkImages(){
// Reset status & progress bar
holder.children().removeClass();
dfdLabel.removeClass('label-success label-important');
progressBar.css({ width: 0 });
statusBar.hide();
progress.show();
$holder.children().removeClass();
$dfdLabel.removeClass('label-success label-important');
$progressBar.css({ width: 0 });
$statusBar.hide();
$progress.show();
// Call imagesLoaded with callback, defer the determination, and save the deferred object
var dfd = holder.imagesLoaded(function( $images, $proper, $broken ){
// Call imagesLoaded with multiple callbacks, and save the deferred object
var dfd = $holder.imagesLoaded({
callback: function($images, $proper, $broken){
totalLabel.text( $images.length );
properLabel.text( $proper.length );
brokenLabel.text( $broken.length );
$totalLabel.text( $images.length );
$properLabel.text( $proper.length );
$brokenLabel.text( $broken.length );
}, true);
},
progress: function (isBroken, $images, $proper, $broken) {
// Deferred magic
dfd.progress(function( isBroken, $images, $proper, $broken ){
var loadingSpan = this.siblings('.loading');
var loadingSpan = this.siblings('.loading');
if( isBroken ){
loadingSpan.removeClass('loading').addClass('broken');
} else {
loadingSpan.fadeOut(200, function(){ $(this).remove(); });
}
if( isBroken ){
loadingSpan.removeClass('loading').addClass('broken');
} else {
loadingSpan.fadeOut(200, function(){ $(this).remove(); });
}
$progressBar.css({ width: Math.round( ( ( $proper.length + $broken.length ) * 100 ) / $images.length ) + '%' });
progressBar.css({ width: Math.round( ( ( $proper.length + $broken.length ) * 100 ) / $images.length ) + '%' });
}
});
}).always(function(){
// Subsequent deferred method registration (not to be used with progress method)
dfd.always(function(){
var dfdState = dfd.state();
dfdLabel.addClass( 'label-' + ( dfdState === 'resolved' ? 'success' : 'important' ) ).text( dfdState );
$dfdLabel.addClass( 'label-' + ( dfdState === 'resolved' ? 'success' : 'important' ) ).text( dfdState );
progress.hide();
statusBar.show();
progressBar.css({ width: 0 });
$progress.hide();
$statusBar.show();
$progressBar.css({ width: 0 });
});
// Start the determination process
dfd.start();
}
// Add images to holder; 20% of images will be broken by default
@@ -161,7 +161,7 @@ jQuery(function($){
brokenPercentile = 10;
}
holder.loremImages( 600, 800, { count: count, randomWidth: 100, itemBuilder: function( i, url ){
$holder.loremImages( 600, 800, { count: count, randomWidth: 100, itemBuilder: function( i, url ){
url = Math.random()*100 < brokenPercentile ? broken_urls[Math.floor( Math.random() * broken_urls.length )]+'?'+Math.round( Math.random()*1000 ) : url;
@@ -174,7 +174,7 @@ jQuery(function($){
}
// Controls
controlbar.find('[data-action]').click(function(){
$controlbar.find('[data-action]').click(function(){
var el = $(this),
action = el.data('action'),
@@ -187,7 +187,7 @@ jQuery(function($){
break;
case 'removeImages':
holder.children().slice(-count).remove();
$holder.children().slice(-count).remove();
checkImages();
break;
@@ -196,7 +196,7 @@ jQuery(function($){
});
// Click-delete images
holder.on('click', 'li', function(){
$holder.on('click', 'li', function(){
$(this).fadeOut( 200, function(){

View File

@@ -1,10 +1,10 @@
/*! Prism | http://prismjs.com */
(function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={languages:{insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);Object.prototype.toString.call(e)==="[object Object]"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent.trim();if(!f)return;f=f.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\u00a0/g," ");var l={element:r,language:o,grammar:u,code:f};t.hooks.run("before-highlight",l);if(i&&self.Worker){var c=new Worker(t.filename);c.onmessage=function(e){l.highlightedCode=n.stringify(JSON.parse(e.data));l.element.innerHTML=l.highlightedCode;s&&s.call(l.element);t.hooks.run("after-highlight",l)};c.postMessage(JSON.stringify({language:l.language,code:l.code}))}else{l.highlightedCode=t.highlight(l.code,l.grammar);l.element.innerHTML=l.highlightedCode;s&&s.call(r);t.hooks.run("after-highlight",l)}},highlight:function(e,r){return n.stringify(t.tokenize(e,r))},tokenize:function(e,n){var r=t.Token,i=[e],s=n.rest;if(s){for(var o in s)n[o]=s[o];delete n.rest}e:for(var o in n){if(!n.hasOwnProperty(o)||!n[o])continue;var u=n[o],a=u.inside,f=!!u.lookbehind||0;u=u.pattern||u;for(var l=0;l<i.length;l++){var c=i[l];if(i.length>e.length)break e;if(c instanceof r)continue;u.lastIndex=0;var h=u.exec(c);if(h){f&&(f=h[1].length);var p=h.index-1+f,h=h[0].slice(f),d=h.length,v=p+d,m=c.slice(0,p+1),g=c.slice(v+1),y=[l,1];m&&y.push(m);var b=new r(o,a?t.tokenize(h,a):h);y.push(b);g&&y.push(g);Array.prototype.splice.apply(i,y)}}}return i},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]"){for(var r=0;r<e.length;r++)e[r]=n.stringify(e[r]);return e.join("")}var i={type:e.type,content:n.stringify(e.content),tag:"span",classes:["token",e.type],attributes:{}};i.type=="comment"&&(i.attributes.spellcheck="true");t.hooks.run("wrap",i);var s="";for(var o in i.attributes)s+=o+'="'+(i.attributes[o]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+s+">"+i.content+"</"+i.tag+">"};if(!self.document){self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}})();
;(function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={languages:{insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);Object.prototype.toString.call(e)==="[object Object]"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent.trim();if(!f)return;f=f.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\u00a0/g," ");var l={element:r,language:o,grammar:u,code:f};t.hooks.run("before-highlight",l);if(i&&self.Worker){var c=new Worker(t.filename);c.onmessage=function(e){l.highlightedCode=n.stringify(JSON.parse(e.data));l.element.innerHTML=l.highlightedCode;s&&s.call(l.element);t.hooks.run("after-highlight",l)};c.postMessage(JSON.stringify({language:l.language,code:l.code}))}else{l.highlightedCode=t.highlight(l.code,l.grammar);l.element.innerHTML=l.highlightedCode;s&&s.call(r);t.hooks.run("after-highlight",l)}},highlight:function(e,r){return n.stringify(t.tokenize(e,r))},tokenize:function(e,n){var r=t.Token,i=[e],s=n.rest;if(s){for(var o in s)n[o]=s[o];delete n.rest}e:for(var o in n){if(!n.hasOwnProperty(o)||!n[o])continue;var u=n[o],a=u.inside,f=!!u.lookbehind||0;u=u.pattern||u;for(var l=0;l<i.length;l++){var c=i[l];if(i.length>e.length)break e;if(c instanceof r)continue;u.lastIndex=0;var h=u.exec(c);if(h){f&&(f=h[1].length);var p=h.index-1+f,h=h[0].slice(f),d=h.length,v=p+d,m=c.slice(0,p+1),g=c.slice(v+1),y=[l,1];m&&y.push(m);var b=new r(o,a?t.tokenize(h,a):h);y.push(b);g&&y.push(g);Array.prototype.splice.apply(i,y)}}}return i},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]"){for(var r=0;r<e.length;r++)e[r]=n.stringify(e[r]);return e.join("")}var i={type:e.type,content:n.stringify(e.content),tag:"span",classes:["token",e.type],attributes:{}};i.type=="comment"&&(i.attributes.spellcheck="true");t.hooks.run("wrap",i);var s="";for(var o in i.attributes)s+=o+'="'+(i.attributes[o]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+s+">"+i.content+"</"+i.tag+">"};if(!self.document){self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}})();
Prism.languages.markup={comment:/&lt;!--[\w\W]*?--(&gt;|&gt;)/g,prolog:/&lt;\?.+?\?&gt;/,doctype:/&lt;!DOCTYPE.+?&gt;/,cdata:/&lt;!\[CDATA\[[\w\W]+?]]&gt;/i,tag:{pattern:/&lt;\/?[\w:-]+\s*[\w\W]*?&gt;/gi,inside:{tag:{pattern:/^&lt;\/?[\w:-]+/i,inside:{punctuation:/^&lt;\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(('|")[\w\W]*?(\2)|[^\s>]+)/gi,inside:{punctuation:/=/g}},punctuation:/\/?&gt;/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/&amp;#?[\da-z]{1,8};/gi};Prism.hooks.add("wrap",function(e){e.type==="entity"&&(e.attributes.title=e.content.replace(/&amp;/,"&"))});
Prism.languages.css={comment:/\/\*[\w\W]*?\*\//g,atrule:/@[\w-]+?(\s+.+)?(?=\s*{|\s*;)/gi,url:/url\((["']?).*?\1\)/gi,selector:/[^\{\}\s][^\{\}]*(?=\s*\{)/g,property:/(\b|\B)[a-z-]+(?=\s*:)/ig,string:/("|')(\\?.)*?\1/g,important:/\B!important\b/gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[\{\};:]/g};Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{style:{pattern:/(&lt;|<)style[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/style(>|&gt;)/ig,inside:{tag:{pattern:/(&lt;|<)style[\w\W]*?(>|&gt;)|(&lt;|<)\/style(>|&gt;)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css}}});
Prism.languages.javascript={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0},keyword:/\b(var|let|if|else|while|do|for|return|in|instanceof|function|new|with|typeof|try|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,number:/\b-?(0x)?\d*\.?\d+\b/g,operator:/[-+]{1,2}|!|=?&lt;|=?&gt;|={1,2}|(&amp;){1,2}|\|?\||\?|\*|\//g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(&lt;|<)script[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/script(>|&gt;)/ig,inside:{tag:{pattern:/(&lt;|<)script[\w\W]*?(>|&gt;)|(&lt;|<)\/script(>|&gt;)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});
Prism.languages.java={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/g,lookbehind:true},string:/("|')(\\?.)*?\1/g,keyword:/\b(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)\b/g,"boolean":/\b(true|false)\b/g,number:/\b-?(0x)?\d*\.?\d+\b/g,operator:/[-+]{1,2}|!|=?<|=?>|={1,2}|(&){1,2}|\|?\||\?|\*|\/|%|\^|(<){2}|($gt;){2,3}|:|~/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g}
Prism.languages.java={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/g,lookbehind:true},string:/("|')(\\?.)*?\1/g,keyword:/\b(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)\b/g,"boolean":/\b(true|false)\b/g,number:/\b-?(0x)?\d*\.?\d+\b/g,operator:/[-+]{1,2}|!|=?<|=?>|={1,2}|(&){1,2}|\|?\||\?|\*|\/|%|\^|(<){2}|($gt;){2,3}|:|~/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};
/*! jQuery LoremImages v1.0.1 | https://github.com/Darsain/loremImages */
(function(b){b.fn.loremImages=function(e,d,j){var a=b.extend({},b.fn.loremImages.defaults,j);return this.each(function(c,k){var f=b(k),g="";for(c=0;c<a.count;c++){var h=e+Math.round(Math.random()*a.randomWidth),i=d+Math.round(Math.random()*a.randomHeight);g+=a.itemBuilder.call(f,c,"//lorempixel.com/"+(a.grey?"g/":"")+h+"/"+i+"/"+(a.category?a.category+"/":"")+"?"+Math.round(Math.random()*1E3),h,i)}f.append(g)})};b.fn.loremImages.defaults={count:10,grey:0,randomWidth:0,randomHeight:0,category:0,itemBuilder:function(e,
d){return'<img src="'+d+'" alt="Lorempixel">'}}})(jQuery);
;(function(b){b.fn.loremImages=function(e,d,j){var a=b.extend({},b.fn.loremImages.defaults,j);return this.each(function(c,k){var f=b(k),g="";for(c=0;c<a.count;c++){var h=e+Math.round(Math.random()*a.randomWidth),i=d+Math.round(Math.random()*a.randomHeight);g+=a.itemBuilder.call(f,c,"//lorempixel.com/"+(a.grey?"g/":"")+h+"/"+i+"/"+(a.category?a.category+"/":"")+"?"+Math.round(Math.random()*1E3),h,i)}f.append(g)})};b.fn.loremImages.defaults={count:10,grey:0,randomWidth:0,randomHeight:0,category:0,itemBuilder:function(e,
d){return'<img src="'+d+'" alt="Lorempixel">'}}})(jQuery);