diff --git a/wp-admin/custom-header.php b/wp-admin/custom-header.php index 89a0b423b..5bf250ef2 100644 --- a/wp-admin/custom-header.php +++ b/wp-admin/custom-header.php @@ -140,6 +140,8 @@ class Custom_Image_Header { function js_includes() { $step = $this->step(); + if ( 1 == $step ) + wp_enqueue_script('jquery-masonry'); if ( ( 1 == $step || 3 == $step ) && $this->header_text() ) wp_enqueue_script('farbtastic'); elseif ( 2 == $step ) @@ -637,7 +639,13 @@ class Custom_Image_Header { - + header_text() ) : ?> diff --git a/wp-includes/js/jquery/jquery.masonry.dev.js b/wp-includes/js/jquery/jquery.masonry.dev.js new file mode 100644 index 000000000..3ddae3ec9 --- /dev/null +++ b/wp-includes/js/jquery/jquery.masonry.dev.js @@ -0,0 +1,494 @@ +/** + * jQuery Masonry v2.1.02 + * A dynamic layout plugin for jQuery + * The flip-side of CSS Floats + * http://masonry.desandro.com + * + * Licensed under the MIT license. + * Copyright 2011 David DeSandro + */ + +(function( window, $, undefined ){ + + /* + * smartresize: debounced resize event for jQuery + * + * latest version and complete README available on Github: + * https://github.com/louisremi/jquery.smartresize.js + * + * Copyright 2011 @louis_remi + * Licensed under the MIT license. + */ + + var $event = $.event, + resizeTimeout; + + $event.special.smartresize = { + setup: function() { + $(this).bind( "resize", $event.special.smartresize.handler ); + }, + teardown: function() { + $(this).unbind( "resize", $event.special.smartresize.handler ); + }, + handler: function( event, execAsap ) { + // Save the context + var context = this, + args = arguments; + + // set correct event type + event.type = "smartresize"; + + if ( resizeTimeout ) { clearTimeout( resizeTimeout ); } + resizeTimeout = setTimeout(function() { + jQuery.event.handle.apply( context, args ); + }, execAsap === "execAsap"? 0 : 100 ); + } + }; + + $.fn.smartresize = function( fn ) { + return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] ); + }; + + + +// ========================= Masonry =============================== + + + // our "Widget" object constructor + $.Mason = function( options, element ){ + this.element = $( element ); + + this._create( options ); + this._init(); + }; + + $.Mason.settings = { + isResizable: true, + isAnimated: false, + animationOptions: { + queue: false, + duration: 500 + }, + gutterWidth: 0, + isRTL: false, + isFitWidth: false, + containerStyle: { + position: 'relative' + } + }; + + $.Mason.prototype = { + + _filterFindBricks: function( $elems ) { + var selector = this.options.itemSelector; + // if there is a selector + // filter/find appropriate item elements + return !selector ? $elems : $elems.filter( selector ).add( $elems.find( selector ) ); + }, + + _getBricks: function( $elems ) { + var $bricks = this._filterFindBricks( $elems ) + .css({ position: 'absolute' }) + .addClass('masonry-brick'); + return $bricks; + }, + + // sets up widget + _create : function( options ) { + + this.options = $.extend( true, {}, $.Mason.settings, options ); + this.styleQueue = []; + + // get original styles in case we re-apply them in .destroy() + var elemStyle = this.element[0].style; + this.originalStyle = { + // get height + height: elemStyle.height || '' + }; + // get other styles that will be overwritten + var containerStyle = this.options.containerStyle; + for ( var prop in containerStyle ) { + this.originalStyle[ prop ] = elemStyle[ prop ] || ''; + } + + this.element.css( containerStyle ); + + this.horizontalDirection = this.options.isRTL ? 'right' : 'left'; + + this.offset = { + x: parseInt( this.element.css( 'padding-' + this.horizontalDirection ), 10 ), + y: parseInt( this.element.css( 'padding-top' ), 10 ) + }; + + this.isFluid = this.options.columnWidth && typeof this.options.columnWidth === 'function'; + + // add masonry class first time around + var instance = this; + setTimeout( function() { + instance.element.addClass('masonry'); + }, 0 ); + + // bind resize method + if ( this.options.isResizable ) { + $(window).bind( 'smartresize.masonry', function() { + instance.resize(); + }); + } + + + // need to get bricks + this.reloadItems(); + + }, + + // _init fires when instance is first created + // and when instance is triggered again -> $el.masonry(); + _init : function( callback ) { + this._getColumns(); + this._reLayout( callback ); + }, + + option: function( key, value ){ + // set options AFTER initialization: + // signature: $('#foo').bar({ cool:false }); + if ( $.isPlainObject( key ) ){ + this.options = $.extend(true, this.options, key); + } + }, + + // ====================== General Layout ====================== + + // used on collection of atoms (should be filtered, and sorted before ) + // accepts atoms-to-be-laid-out to start with + layout : function( $bricks, callback ) { + + // place each brick + for (var i=0, len = $bricks.length; i < len; i++) { + this._placeBrick( $bricks[i] ); + } + + // set the size of the container + var containerSize = {}; + containerSize.height = Math.max.apply( Math, this.colYs ); + if ( this.options.isFitWidth ) { + var unusedCols = 0, + i = this.cols; + // count unused columns + while ( --i ) { + if ( this.colYs[i] !== 0 ) { + break; + } + unusedCols++; + } + // fit container to columns that have been used; + containerSize.width = (this.cols - unusedCols) * this.columnWidth - this.options.gutterWidth; + } + this.styleQueue.push({ $el: this.element, style: containerSize }); + + // are we animating the layout arrangement? + // use plugin-ish syntax for css or animate + var styleFn = !this.isLaidOut ? 'css' : ( + this.options.isAnimated ? 'animate' : 'css' + ), + animOpts = this.options.animationOptions; + + // process styleQueue + var obj; + for (i=0, len = this.styleQueue.length; i < len; i++) { + obj = this.styleQueue[i]; + obj.$el[ styleFn ]( obj.style, animOpts ); + } + + // clear out queue for next time + this.styleQueue = []; + + // provide $elems as context for the callback + if ( callback ) { + callback.call( $bricks ); + } + + this.isLaidOut = true; + }, + + // calculates number of columns + // i.e. this.columnWidth = 200 + _getColumns : function() { + var container = this.options.isFitWidth ? this.element.parent() : this.element, + containerWidth = container.width(); + + // use fluid columnWidth function if there + this.columnWidth = this.isFluid ? this.options.columnWidth( containerWidth ) : + // if not, how about the explicitly set option? + this.options.columnWidth || + // or use the size of the first item + this.$bricks.outerWidth(true) || + // if there's no items, use size of container + containerWidth; + + this.columnWidth += this.options.gutterWidth; + + this.cols = Math.floor( ( containerWidth + this.options.gutterWidth ) / this.columnWidth ); + this.cols = Math.max( this.cols, 1 ); + + }, + + // layout logic + _placeBrick: function( brick ) { + var $brick = $(brick), + colSpan, groupCount, groupY, groupColY, j; + + //how many columns does this brick span + colSpan = Math.ceil( $brick.outerWidth(true) / + ( this.columnWidth + this.options.gutterWidth ) ); + colSpan = Math.min( colSpan, this.cols ); + + if ( colSpan === 1 ) { + // if brick spans only one column, just like singleMode + groupY = this.colYs + } else { + // brick spans more than one column + // how many different places could this brick fit horizontally + groupCount = this.cols + 1 - colSpan; + groupY = []; + + // for each group potential horizontal position + for ( j=0; j < groupCount; j++ ) { + // make an array of colY values for that one group + groupColY = this.colYs.slice( j, j+colSpan ); + // and get the max value of the array + groupY[j] = Math.max.apply( Math, groupColY ); + } + + } + + // get the minimum Y value from the columns + var minimumY = Math.min.apply( Math, groupY ), + shortCol = 0; + + // Find index of short column, the first from the left + for (var i=0, len = groupY.length; i < len; i++) { + if ( groupY[i] === minimumY ) { + shortCol = i; + break; + } + } + + // position the brick + var position = { + top: minimumY + this.offset.y + }; + // position.left or position.right + position[ this.horizontalDirection ] = this.columnWidth * shortCol + this.offset.x; + this.styleQueue.push({ $el: $brick, style: position }); + + // apply setHeight to necessary columns + var setHeight = minimumY + $brick.outerHeight(true), + setSpan = this.cols + 1 - len; + for ( i=0; i < setSpan; i++ ) { + this.colYs[ shortCol + i ] = setHeight; + } + + }, + + + resize: function() { + var prevColCount = this.cols; + // get updated colCount + this._getColumns(); + if ( this.isFluid || this.cols !== prevColCount ) { + // if column count has changed, trigger new layout + this._reLayout(); + } + }, + + + _reLayout : function( callback ) { + // reset columns + var i = this.cols; + this.colYs = []; + while (i--) { + this.colYs.push( 0 ); + } + // apply layout logic to all bricks + this.layout( this.$bricks, callback ); + }, + + // ====================== Convenience methods ====================== + + // goes through all children again and gets bricks in proper order + reloadItems : function() { + this.$bricks = this._getBricks( this.element.children() ); + }, + + + reload : function( callback ) { + this.reloadItems(); + this._init( callback ); + }, + + + // convienence method for working with Infinite Scroll + appended : function( $content, isAnimatedFromBottom, callback ) { + if ( isAnimatedFromBottom ) { + // set new stuff to the bottom + this._filterFindBricks( $content ).css({ top: this.element.height() }); + var instance = this; + setTimeout( function(){ + instance._appended( $content, callback ); + }, 1 ); + } else { + this._appended( $content, callback ); + } + }, + + _appended : function( $content, callback ) { + var $newBricks = this._getBricks( $content ); + // add new bricks to brick pool + this.$bricks = this.$bricks.add( $newBricks ); + this.layout( $newBricks, callback ); + }, + + // removes elements from Masonry widget + remove : function( $content ) { + this.$bricks = this.$bricks.not( $content ); + $content.remove(); + }, + + // destroys widget, returns elements and container back (close) to original style + destroy : function() { + + this.$bricks + .removeClass('masonry-brick') + .each(function(){ + this.style.position = ''; + this.style.top = ''; + this.style.left = ''; + }); + + // re-apply saved container styles + var elemStyle = this.element[0].style; + for ( var prop in this.originalStyle ) { + elemStyle[ prop ] = this.originalStyle[ prop ]; + } + + this.element + .unbind('.masonry') + .removeClass('masonry') + .removeData('masonry'); + + $(window).unbind('.masonry'); + + } + + }; + + + // ======================= imagesLoaded Plugin =============================== + /*! + * jQuery imagesLoaded plugin v1.1.0 + * http://github.com/desandro/imagesloaded + * + * MIT License. by Paul Irish et al. + */ + + + // $('#my-container').imagesLoaded(myFunction) + // or + // $('img').imagesLoaded(myFunction) + + // execute a callback when all images have loaded. + // needed because .load() doesn't work on cached images + + // callback function gets image collection as argument + // `this` is the container + + $.fn.imagesLoaded = function( callback ) { + var $this = this, + $images = $this.find('img').add( $this.filter('img') ), + len = $images.length, + blank = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==', + loaded = []; + + function triggerCallback() { + callback.call( $this, $images ); + } + + function imgLoaded( event ) { + if ( event.target.src !== blank && $.inArray( this, loaded ) === -1 ){ + loaded.push(this); + if ( --len <= 0 ){ + setTimeout( triggerCallback ); + $images.unbind( '.imagesLoaded', imgLoaded ); + } + } + } + + // if no images, trigger immediately + if ( !len ) { + triggerCallback(); + } + + $images.bind( 'load.imagesLoaded error.imagesLoaded', imgLoaded ).each( function() { + // cached images don't fire load sometimes, so we reset src. + var src = this.src; + // webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f + // data uri bypasses webkit log warning (thx doug jones) + this.src = blank; + this.src = src; + }); + + return $this; + }; + + + // helper function for logging errors + // $.error breaks jQuery chaining + var logError = function( message ) { + if ( this.console ) { + console.error( message ); + } + }; + + // ======================= Plugin bridge =============================== + // leverages data method to either create or return $.Mason constructor + // A bit from jQuery UI + // https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js + // A bit from jcarousel + // https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js + + $.fn.masonry = function( options ) { + if ( typeof options === 'string' ) { + // call method + var args = Array.prototype.slice.call( arguments, 1 ); + + this.each(function(){ + var instance = $.data( this, 'masonry' ); + if ( !instance ) { + logError( "cannot call methods on masonry prior to initialization; " + + "attempted to call method '" + options + "'" ); + return; + } + if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) { + logError( "no such method '" + options + "' for masonry instance" ); + return; + } + // apply method + instance[ options ].apply( instance, args ); + }); + } else { + this.each(function() { + var instance = $.data( this, 'masonry' ); + if ( instance ) { + // apply options & init + instance.option( options || {} ); + instance._init(); + } else { + // initialize new instance + $.data( this, 'masonry', new $.Mason( options, this ) ); + } + }); + } + return this; + }; + +})( window, jQuery ); diff --git a/wp-includes/js/jquery/jquery.masonry.js b/wp-includes/js/jquery/jquery.masonry.js new file mode 100644 index 000000000..c0e864e8e --- /dev/null +++ b/wp-includes/js/jquery/jquery.masonry.js @@ -0,0 +1,8 @@ +(function(d,e,f){var a=e.event,c;a.special.smartresize={setup:function(){e(this).bind("resize",a.special.smartresize.handler)},teardown:function(){e(this).unbind("resize",a.special.smartresize.handler)},handler:function(j,g){var i=this,h=arguments;j.type="smartresize";if(c){clearTimeout(c)}c=setTimeout(function(){jQuery.event.handle.apply(i,h)},g==="execAsap"?0:100)}};e.fn.smartresize=function(g){return g?this.bind("smartresize",g):this.trigger("smartresize",["execAsap"])};e.Mason=function(g,h){this.element=e(h);this._create(g);this._init()};e.Mason.settings={isResizable:true,isAnimated:false,animationOptions:{queue:false,duration:500},gutterWidth:0,isRTL:false,isFitWidth:false,containerStyle:{position:"relative"}};e.Mason.prototype={_filterFindBricks:function(h){var g=this.options.itemSelector;return !g?h:h.filter(g).add(h.find(g))},_getBricks:function(h){var g=this._filterFindBricks(h).css({position:"absolute"}).addClass("masonry-brick");return g},_create:function(i){this.options=e.extend(true,{},e.Mason.settings,i);this.styleQueue=[];var h=this.element[0].style;this.originalStyle={height:h.height||""};var j=this.options.containerStyle;for(var k in j){this.originalStyle[k]=h[k]||""}this.element.css(j);this.horizontalDirection=this.options.isRTL?"right":"left";this.offset={x:parseInt(this.element.css("padding-"+this.horizontalDirection),10),y:parseInt(this.element.css("padding-top"),10)};this.isFluid=this.options.columnWidth&&typeof this.options.columnWidth==="function";var g=this;setTimeout(function(){g.element.addClass("masonry")},0);if(this.options.isResizable){e(d).bind("smartresize.masonry",function(){g.resize()})}this.reloadItems()},_init:function(g){this._getColumns();this._reLayout(g)},option:function(g,h){if(e.isPlainObject(g)){this.options=e.extend(true,this.options,g)}},layout:function(o,p){for(var m=0,n=o.length;madd( 'jquery-table-hotkeys', "/wp-includes/js/jquery/jquery.table-hotkeys$suffix.js", array('jquery', 'jquery-hotkeys'), false, 1 ); $scripts->add( 'jquery-postmessage', "/wp-includes/js/jquery/jquery.postmessage$suffix.js", array('jquery'), '0.5', 1 ); + $scripts->add( 'jquery-masonry', "/wp-includes/js/jquery/jquery.masonry$suffix.js", array('jquery'), '2.1.02', 1 ); + $scripts->add( 'thickbox', "/wp-includes/js/thickbox/thickbox.js", array('jquery'), '3.1-20111117', 1 ); $scripts->localize( 'thickbox', 'thickboxL10n', array( 'next' => __('Next >'),