/*! * moving boxes v2.3.4 * by chris coyier * http://css-tricks.com/moving-boxes/ */ /* �������������֮�� www.lanrenzhijia.com ת����ע������ */ /*jshint browser:true, jquery:true */ ;(function($){ "use strict"; $.movingboxes = function(el, options){ // to avoid scope issues, use 'base' instead of 'this' // to reference this class from internal events and functions. var o, base = this; // access to jquery and dom versions of element base.$el = $(el).addclass('mb-slider'); base.el = el; // add a reverse reference to the dom object base.$el.data('movingboxes', base); base.init = function(){ base.options = o = $.extend({}, $.movingboxes.defaultoptions, options); // setup formatting (to reduce the amount of initial html) base.$el.wrap('
'); // defaults base.$window = base.$el.parent(); // mb-scroll base.$wrap = base.$window.parent() // mb-wrapper .prepend('') .append('
'); base.$panels = base.$el.children().addclass('mb-panel') base.runtime = $('.mb-slider').index(base.$el) + 1; // get index (run time) of this slider on the page base.regex = new regexp('slider' + base.runtime + '=(\\d+)', 'i'); // hash tag regex base.initialized = false; base.currentlymoving = false; base.curpanel = (o.initanimation) ? 1 : base.gethash() || o.startpanel; // save original slider width base.width = (o.width) ? parseint(o.width,10) : base.$el.width(); // save panel width, o.panelwidth originally a fraction (0.5 of o.width) if defined, or get first panel width // now can be set after initialization to resize using fraction (value <= 2) or px (all values > 2) base.pwidth = (o.panelwidth) ? (o.panelwidth <=2 ? o.panelwidth * base.width : o.panelwidth) : base.$panels.eq(0).width(); // set up click on left/right arrows base.$left = base.$wrap.find('.mb-left').click(function(){ base.goback(); return false; }); base.$right = base.$wrap.find('.mb-right').click(function(){ base.goforward(); return false; }); // code to run to update movingboxes when the number of panels change base.update({}, false); // make sure current panel is centered base.setwrap(base.curpanel); // go to clicked panel base.$el.delegate('.mb-panel', 'click', function(e){ if (!$(this).hasclass(o.currentpanel)) { e.preventdefault(); // prevent non-current panel links from working base.change( base.$panels.index($(this)) + base.adj, {}, true ); } }); // activate moving box on click or when an internal link obtains focus base.$wrap.click(function(){ if (!base.$wrap.hasclass('mb-active-slider')) { base.active(); } }); base.$panels.delegate('a', 'focus' ,function(e){ e.preventdefault(); // focused link centered in moving box var loc = base.$panels.index($(this).closest('.mb-panel')) + base.adj; if (loc !== base.curpanel){ base.change( loc, {}, true ); } }); // add keyboard navigation $(document).keyup(function(e){ // ignore arrow/space keys if inside a form element if (e.target.tagname.match('textarea|input|select')) { return; } switch (e.which) { case 39: case 32: // right arrow & space if (base.$wrap.is('.mb-active-slider')){ base.goforward(); } break; case 37: // left arrow if (base.$wrap.is('.mb-active-slider')){ base.goback(); } break; } }); // bind events $.each('preinit initialized initchange beforeanimation completed'.split(' '), function(i,evt){ if ($.isfunction(o[evt])){ base.$el.bind(evt + '.movingboxes', o[evt]); } }); base.$el.trigger( 'preinit.movingboxes', [ base, base.curpanel ] ); }; // update the panel, flag is used to prevent events from firing base.update = function(callback, flag){ // infinite loop base.$el.children('.cloned').remove(); base.$panels = base.$el.children(); base.adj = (o.wrap && base.$panels.length > 1) ? 0 : 1; // count adjustment for infinite panels base.width = (o.width) ? parseint(o.width,10) : base.width; base.$wrap.css('width', base.width); // set wrapper width if (o.wrap && base.$panels.length > 1) { base.$el.prepend( base.$panels.filter(':last').clone().addclass('cloned') ); base.$el.append( base.$panels.filter(':first').clone().addclass('cloned') ); base.$el.find('.cloned').each(function(){ // disable all focusable elements in cloned panels to prevent shifting the panels by tabbing $(this).find('a,input,textarea,select,button,area').removeattr('name').attr('disabled', 'disabled'); $(this).find('[id]').andself().removeattr('id'); }); } // set up panes & content sizes // defined $panels again to include cloned panels base.$panels = base.$el.children() .addclass('mb-panel') // inner wrap of each panel .each(function(){ if ($(this).find('.mb-inside').length === 0) { $(this).wrapinner('
'); } }); base.totalpanels = base.$panels.filter(':not(.cloned)').length; // don't include cloned panels in total // in case current panel no longer exists if (base.totalpanels <= 1) { base.curpanel = 1; } base.setsizes(flag); base.buildnav(); base.change(base.curpanel, callback, flag); // initialize from first panel... then scroll to start panel // check panel height after all images load base.imagesloaded(function(){ base.setsizes(false); base.setwrap(base.curpanel); // animate to chosen start panel - starting from the first panel makes it look better if (!base.initialized){ settimeout(function(){ base.initialized = true; base.change(base.gethash() || o.startpanel, {}, false); base.$el.trigger( 'initialized.movingboxes', [ base, base.curpanel ] ); }, o.speed * 2 ); } }); }; base.setsizes = function(flag){ // include padding & margins around the panels base.padding = parseint(base.$panels.css('padding-left'), 10) + parseint(base.$panels.css('margin-left'), 10); // save 'cur' numbers (current larger panel size), use stored sizes if they exist base.curwidth = (o.panelwidth) ? (o.panelwidth <=2 ? o.panelwidth * base.width : o.panelwidth) : base.pwidth; // save 'reg' (reduced size) numbers base.regwidth = base.curwidth * o.reducedsize; // set image heights so base container height is correctly set base.$panels.css({ width: base.curwidth,margintop: '100' }); // make all panels big // save each panel height... script will resize container as needed // make sure current panel css is applied before measuring base.$panels.eq(base.curpanel - base.adj).addclass(o.currentpanel); base.heights = base.$panels.css('height','auto').map(function(i,e){ return $(e).outerheight(true); }).get(); base.returntonormal(base.curpanel, 0); // resize new panel, animation time base.growbigger(base.curpanel, 0, flag); base.updatearrows(base.curpanel); // make base container wide enough to contain all the panels base.$el.css({ position : 'absolute', // add a bit more width to each box (base.padding *2; then add 1/2 overall width in case only one panel exists) width : (base.curwidth + base.padding * 2) * base.$panels.length + (base.width - base.curwidth) / 2, height : math.max.apply( this, base.heights ) + 10, // add padding so scrollleft = 0 centers the left-most panel (needed because scrollleft cannot be < 0) 'padding-left' : (base.width - base.curwidth) / 2 }); base.$window.css({ height : (o.fixedheight) ? math.max.apply( this, base.heights ) : base.heights[base.curpanel - base.adj] }); }; // creates the numbered navigation links base.buildnav = function() { if (base.$nav) { base.$nav.find('.mb-links').empty(); } else { base.$nav = $('
').appendto(base.$wrap); } if (o.buildnav && base.totalpanels > 1) { var t, j, a = '', $a; base.$panels.filter(':not(.cloned)').each(function(i){ j = i + 1; a = ''; $a = $(a); // if a formatter function is present, use it if ($.isfunction(o.navformatter)) { t = o.navformatter(j, $(this)); if (typeof(t) === "string") { $a.html(t); } else { $a = $('', t); } } else { $a.html(j); } $a .appendto(base.$nav.find('.mb-links')) .addclass('mb-link mb-panel' + j) .data('index', j); }); base.$nav .find('a.mb-link').bind('click', function() { base.change( $(this).data('index') ); return false; }); } }; // resize panels to normal base.returntonormal = function(num, time){ var panels = base.$panels.not(':eq(' + (num - base.adj) + ')').removeclass(o.currentpanel); if (o.reducedsize === 1) { panels.css({ width: base.regwidth }); // excluding fontsize change to prevent video flicker } else { panels.stop(true,false).animate({ width: base.regwidth,margintop:'100' }, (time === 0) ? 0 : o.speed); } }; // zoom in on selected panel base.growbigger = function(num, time, flag){ var panels = base.$panels.eq(num - base.adj); if (o.reducedsize === 1) { panels.css({ width: base.curwidth }); // excluding fontsize change to prevent video flicker // time delay prevents click outer panel from following links - fixes issue #67 settimeout(function(){ base.completed(num, flag); }, (time === 0) ? 0 : o.speed); } else { panels.stop(true,false).animate({ width: base.curwidth,margintop:'0' }, (time === 0) ? 0 : o.speed, function(){ base.completed(num, flag); }); } }; // instantly center the indicated panel base.setwrap = function(panel){ if (base.totalpanels >= 1) { base.growbigger(panel, 0, false); var leftvalue = base.$panels.eq(panel - base.adj).position().left - (base.width - base.curwidth) / 2 + base.padding; base.$window.scrollleft(leftvalue); } }; base.completed = function(num, flag){ // add current panel class after animating in case it has sizing parameters var loc = base.$panels.eq(num - base.adj); if (!loc.hasclass('cloned')) { loc.addclass(o.currentpanel); } if (flag !== false) { base.$el.trigger( 'completed.movingboxes', [ base, num ] ); } }; // go forward/back base.goforward = function(callback){ if (base.initialized) { base.change(base.curpanel + 1, callback); } }; base.goback = function(callback){ if (base.initialized) { base.change(base.curpanel - 1, callback); } }; // change view to display selected panel base.change = function(curpanel, callback, flag){ if (base.totalpanels < 1) { if (typeof(callback) === 'function') { callback(base); } return; } var ani, leftvalue, wrapped = false; flag = flag !== false; // check if curpanel is a jquery selector or object // $('' + curpanel) needed because $(3) = [3], but $('3') = [] if ($('' + curpanel).length || (curpanel instanceof $ && $(curpanel).length)) { curpanel = $(curpanel).closest('.mb-panel').index() + base.adj; } else { // make sure it's a number and not a string curpanel = parseint(curpanel, 10); } if (base.initialized && flag) { // make this moving box active if (!base.$wrap.hasclass('mb-active-slider')) { base.active(); } // initchange event - has extra parameter with targeted panel (not cleaned) base.$el.trigger( 'initchange.movingboxes', [ base, curpanel ] ); } // make infinite scrolling work if (o.wrap) { if (curpanel > base.totalpanels) { wrapped = true; curpanel = 1; base.returntonormal(0, 0); base.setwrap(0); } else if (curpanel === 0) { wrapped = false; curpanel = base.totalpanels; base.setwrap(curpanel + 1); } } if ( curpanel < base.adj ) { curpanel = (o.wrap) ? base.totalpanels : 1; } if ( curpanel > base.totalpanels - base.adj ) { curpanel = (o.wrap) ? 1 : base.totalpanels; } // abort if panel is already animating // animation callback needed to clear this flag, but there is no animation before base.initialized is set if (base.curpanel !== curpanel && (!base.currentlymoving || !base.initialized)) { // set animation flag; animation callback will clear this flag base.currentlymoving = !o.stopanimation; // center panel in scroll window base.$curpanel = base.$panels.eq(curpanel - base.adj); leftvalue = base.$curpanel.position().left - (base.width - base.curwidth) / 2 + base.padding; // when scrolling right, add the difference of the larger current panel width if (base.initialized && (curpanel > base.curpanel || wrapped)) { leftvalue -= ( base.curwidth - base.regwidth ); } ani = (o.fixedheight) ? { scrollleft : leftvalue } : { scrollleft: leftvalue, height: base.heights[curpanel - base.adj] }; base.curpanel = curpanel; // before animation trigger if (base.initialized && flag) { base.$el.trigger( 'beforeanimation.movingboxes', [ base, curpanel ] ); } if (o.delaybeforeanimate) { // delay starting slide animation settimeout(function(){ base.animateboxes(curpanel, ani, flag, callback); }, parseint(o.delaybeforeanimate, 10) || 0); } else { base.animateboxes(curpanel, ani, flag, callback); } } else { base.endanimation(); } }; base.animateboxes = function(curpanel, ani, flag, callback){ // animate the panels base.$window.scrolltop(0).stop(true,false).animate( ani, { queue : false, duration : o.speed, easing : o.easing, complete : function(){ if (base.initialized) { base.$window.scrolltop(0); // opera fix - otherwise, it moves the focus link to the middle of the viewport } base.currentlymoving = false; if (typeof(callback) === 'function') { callback(base); } } } ); base.returntonormal(curpanel); base.growbigger(curpanel, o.speed, flag); base.updatearrows(curpanel); if (o.hashtags && base.initialized) { base.sethash(curpanel); } base.endanimation(); }; base.endanimation = function(){ // update navigation links if (o.buildnav && base.$nav.length) { base.$nav.find('a.mb-link') .removeclass(o.currentpanel) .eq(base.curpanel - 1).addclass(o.currentpanel); } }; base.updatearrows = function(cur){ base.$left.toggleclass(o.disabled, (!o.wrap && cur === base.adj) || base.totalpanels <= 1); base.$right.toggleclass(o.disabled, (!o.wrap && cur === base.totalpanels) || base.totalpanels <= 1); }; // this method tries to find a hash that matches an id and slider-x // if either found, it tries to find a matching item // if that is found as well, then it returns the page number base.gethash = function(){ var h = window.location.hash, i = h.indexof('&'), n = h.match(base.regex); // test for "/#/" or "/#!/" used by the jquery address plugin - $('#/') breaks jquery if (n === null && !/^#&/.test(h) && !/#!?\//.test(h)) { // #quote2&panel1-3&panel3-3 h = h.substring(0, (i >= 0 ? i : h.length)); // ensure the element is in the same slider n = ($(h).length && $(h).closest('.mb-slider')[0] === base.el) ? $(h).closest('.mb-panel').index() + base.adj : null; } else if (n !== null) { // #&panel1-3&panel3-3 n = (o.hashtags) ? parseint(n[1],10) : null; } return (n > base.totalpanels) ? null : n; }; // set hash tags base.sethash = function(n){ var s = 'slider' + base.runtime + "=", h = window.location.hash; if ( typeof h !== 'undefined' ) { window.location.hash = (h.indexof(s) > 0) ? h.replace(base.regex, s + n) : h + "&" + s + n; } }; // make moving box active (for keyboard navigation) base.active = function(){ $('.mb-active-slider').removeclass('mb-active-slider'); base.$wrap.addclass('mb-active-slider'); }; // get: var currentpanel = $('.slider').data('movingboxes').currentpanel(); // returns # of currently selected/enlarged panel // set: var currentpanel = $('.slider').data('movingboxes').currentpanel(2, function(){ alert('done!'); }); // returns and scrolls to 2nd panel base.currentpanel = function(panel, callback){ if (typeof(panel) !== 'undefined') { base.change(panel, callback); // parse in case someone sends a string } return base.curpanel; }; // based on https://github.com/mottie/imagesloaded plugin base.imagesloaded = function(callback, img) { var i, ic, c = true, // complete flag t = img ? $(img) : base.$panels.find('img'), l = t.length; img = img || []; // array of images that didn't complete for ( i = 0; i < l; i++ ) { if (t[i].tagname === "img") { // ie: filesize property = -1 before image has loaded & if image load error, so if false is returned // 10x, then just assume it's an error & call it complete - it's what firefox & webkit does ic = ('filesize' in t[i] && t[i].filesize < 0 && t[i].count > 10) ? true : t[i].complete; // complete flag, checks previous flag status, complete flag & image height // image height may need to be > 20 (or whatever the line-height is) because the alt text is included c = (c && ic && t[i].height !== 0); // complete flag // save non-complete images for next iteration if (ic === false) { img.push(t[i]); // iteration count for ie t[i].count = (t[i].count || 0) + 1; } } } if (c) { // all complete, run the callback if (typeof callback === "function") { callback(); } } else { // some images not loaded, rinse & repeat settimeout(function(){ base.imagesloaded(callback, img); }, 200); } }; // run initializer base.init(); }; $.movingboxes.defaultoptions = { // appearance startpanel : 1, // start with this panel reducedsize : 0.8, // non-current panel size: 80% of panel size fixedheight : false, // if true, slider height set to max panel height; if false, slider height will auto adjust. // behaviour initanimation: true, // if true, movingboxes will initialize, then animate into the starting slide (if not the first slide) stopanimation: false, // if true, movingboxes will force the animation to complete immediately, if the user selects the next panel hashtags : true, // if true, hash tags are enabled wrap : false, // if true, the panel will loop through the panels infinitely buildnav : false, // if true, navigation links will be added navformatter : null, // function which returns the navigation text for each panel easing : 'swing', // anything other than "linear" or "swing" requires the easing plugin // times speed : 500, // animation time in milliseconds delaybeforeanimate : 0, // time to delay in milliseconds before movingboxes animates to the selected panel // selectors & classes currentpanel : 'current', // current panel class tooltipclass : 'tooltip', // added to the navigation, but the title attribute is blank unless the link text-indent is negative disabled : 'disabled',// class added to arrows that are disabled (left arrow when on first panel, right arrow on last panel) // callbacks preinit : null, // callback after the basic movingboxes structure has been built; before "initialized" initialized : null, // callback when movingboxes has completed initialization; all images loaded initchange : null, // callback upon change panel initialization beforeanimation : null, // callback before any animation occurs completed : null // callback after animation completes // deprecated options - but still used to keep the plugin backwards compatible // and allow resizing the overall width and panel width dynamically (i.e. on window resize) // width : 800, // overall width of movingboxes (not including navigation arrows) // panelwidth : 0.5 // current panel width adjusted to 50% of overall width }; $.fn.movingboxes = function(options, callback, flag){ var mb; return this.each(function(){ mb = $(this).data('movingboxes'); // initialize the slider but prevent multiple initializations if ((typeof(options)).match('object|undefined')){ if (mb && options instanceof $ && options.length) { // pass a jquery object to change panels mb.change(options, callback, flag); } else if (mb) { mb.update(callback, flag); } else { (new $.movingboxes(this, options)); } } else if (mb) { // page #, autoplay, one time callback, if flag is false then no events triggered and animation time = 0 mb.change(options, callback, flag); } }); }; // return the movingboxes object $.fn.getmovingboxes = function(){ return this.data('movingboxes'); }; })(jquery); /* �������������֮�� www.lanrenzhijia.com ת����ע������ */