mirror of
https://github.com/twbs/bootstrap.git
synced 2024-12-01 13:24:25 +01:00
kill affix
This commit is contained in:
parent
2eba4458fa
commit
1e9e3316b6
149
dist/js/bootstrap.js
vendored
149
dist/js/bootstrap.js
vendored
@ -181,155 +181,6 @@ $(function () {
|
||||
$.event.special[Bootstrap.TRANSITION_END] = Bootstrap.getSpecialTransitionEndEvent()
|
||||
})
|
||||
|
||||
$(document).on('mq4hsChange', function (e) {
|
||||
$(document.documentElement).toggleClass('bs-true-hover', e.trueHover)
|
||||
})
|
||||
|
||||
/*!
|
||||
* mq4-hover-shim v0.1.0
|
||||
* https://github.com/twbs/mq4-hover-shim
|
||||
* Copyright (c) 2014-2015 Christopher Rebert
|
||||
* Licensed under the MIT License (https://github.com/twbs/mq4-hover-shim/blob/master/LICENSE).
|
||||
*/
|
||||
|
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.mq4HoverShim=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
"use strict";
|
||||
|
||||
var _interopRequireWildcard = function (obj) { return obj && obj.__esModule ? obj : { "default": obj }; };
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Does this UA's primary pointer support true hovering
|
||||
* OR does the UA at least not try to quirkily emulate hovering,
|
||||
* such that :hover CSS styles are appropriate?
|
||||
* Essentially tries to shim the `@media (hover: hover)` CSS media query feature.
|
||||
* @public
|
||||
* @returns {boolean}
|
||||
* @since 0.0.1
|
||||
*/
|
||||
exports.supportsTrueHover = supportsTrueHover;
|
||||
/*eslint-env browser */
|
||||
/*eslint no-var:2*/
|
||||
/* jshint browser: true, esnext: true */
|
||||
/* jshint -W080 */
|
||||
/**
|
||||
* @module mq4HoverShim
|
||||
* @requires jquery
|
||||
*/
|
||||
var $ = (function () {
|
||||
try {
|
||||
var jQuery = _interopRequireWildcard(require("jquery"));
|
||||
|
||||
return jQuery;
|
||||
} catch (importErr) {
|
||||
var globaljQuery = window.$ || window.jQuery || window.Zepto;
|
||||
if (!globaljQuery) {
|
||||
throw new Error("mq4HoverShim needs jQuery (or similar)");
|
||||
}
|
||||
return globaljQuery;
|
||||
}
|
||||
})();
|
||||
|
||||
/** @type {boolean|undefined} */
|
||||
var canTrulyHover = undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @fires mq4HoverShim#mq4hsChange
|
||||
*/
|
||||
function triggerEvent() {
|
||||
$(document).trigger($.Event("mq4hsChange", { bubbles: false, trueHover: canTrulyHover }));
|
||||
}
|
||||
|
||||
// IIFE so we can use `return`s to avoid deeply-nested if-s
|
||||
(function () {
|
||||
if (!window.matchMedia) {
|
||||
// Opera Mini, IE<=9, Android<=2.3, ancient, or obscure; per http://caniuse.com/#feat=matchmedia
|
||||
|
||||
// Opera Mini, Android, and IE Mobile don't support true hovering, so they're what we'll check for.
|
||||
// Other browsers are either:
|
||||
// (a) obscure
|
||||
// (b) touch-based but old enough not to attempt to emulate hovering
|
||||
// (c) old desktop browsers that do support true hovering
|
||||
|
||||
// Explanation of this UA regex:
|
||||
// IE Mobile <9 seems to always have "Windows CE", "Windows Phone", or "IEMobile" in its UA string.
|
||||
// IE Mobile 9 in desktop view doesn't include "IEMobile" or "Windows Phone" in the UA string,
|
||||
// but it instead includes "XBLWP7" and/or "ZuneWP7".
|
||||
canTrulyHover = !/Opera Mini|Android|IEMobile|Windows (Phone|CE)|(XBL|Zune)WP7/.test(navigator.userAgent);
|
||||
|
||||
// Since there won't be any event handlers to fire our events, do the one-and-only firing of it here and now.
|
||||
triggerEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
// CSSWG Media Queries Level 4 draft
|
||||
// http://drafts.csswg.org/mediaqueries/#hover
|
||||
var HOVER_NONE = "(hover: none),(-moz-hover: none),(-ms-hover: none),(-webkit-hover: none)";
|
||||
var HOVER_ON_DEMAND = "(hover: on-demand),(-moz-hover: on-demand),(-ms-hover: on-demand),(-webkit-hover: on-demand)";
|
||||
var HOVER_HOVER = "(hover: hover),(-moz-hover: hover),(-ms-hover: hover),(-webkit-hover: hover)";
|
||||
if (window.matchMedia("" + HOVER_NONE + "," + HOVER_ON_DEMAND + "," + HOVER_HOVER).matches) {
|
||||
// Browser understands the `hover` media feature
|
||||
var hoverCallback = function (mql) {
|
||||
var doesMatch = mql.matches;
|
||||
if (doesMatch !== canTrulyHover) {
|
||||
canTrulyHover = doesMatch;
|
||||
triggerEvent();
|
||||
}
|
||||
};
|
||||
var atHoverQuery = window.matchMedia(HOVER_HOVER);
|
||||
atHoverQuery.addListener(hoverCallback);
|
||||
hoverCallback(atHoverQuery);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for touch support instead.
|
||||
// Touch generally implies that hovering is merely emulated,
|
||||
// which doesn't count as true hovering support for our purposes
|
||||
// due to the quirkiness of the emulation (e.g. :hover being sticky).
|
||||
|
||||
// W3C Pointer Events PR, 16 December 2014
|
||||
// http://www.w3.org/TR/2014/PR-pointerevents-20141216/
|
||||
// Prefixed in IE10, per http://caniuse.com/#feat=pointer
|
||||
if (window.PointerEvent || window.MSPointerEvent) {
|
||||
// Browser supports Pointer Events
|
||||
|
||||
// Browser supports touch if it has touch points
|
||||
/* jshint -W018 */
|
||||
canTrulyHover = !((window.navigator.maxTouchPoints || window.navigator.msMaxTouchPoints) > 0);
|
||||
/* jshint +W018 */
|
||||
triggerEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
// Mozilla's -moz-touch-enabled
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Media_queries#-moz-touch-enabled
|
||||
var touchEnabledQuery = window.matchMedia("(touch-enabled),(-moz-touch-enabled),(-ms-touch-enabled),(-webkit-touch-enabled)");
|
||||
if (touchEnabledQuery.matches) {
|
||||
canTrulyHover = false;
|
||||
triggerEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
// W3C Touch Events REC, 10 October 2013
|
||||
// http://www.w3.org/TR/2013/REC-touch-events-20131010/
|
||||
if ("ontouchstart" in window) {
|
||||
canTrulyHover = false;
|
||||
triggerEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
// UA's pointer is non-touch and thus likely either supports true hovering or at least does not try to emulate it.
|
||||
canTrulyHover = true;
|
||||
triggerEvent();
|
||||
})();function supportsTrueHover() {
|
||||
return canTrulyHover;
|
||||
}
|
||||
exports.__esModule = true;
|
||||
},{"jquery":undefined}]},{},[1])(1)
|
||||
});
|
||||
/** =======================================================================
|
||||
* Bootstrap: alert.js v4.0.0
|
||||
* http://getbootstrap.com/javascript/#alerts
|
||||
|
1
dist/js/npm.js
vendored
1
dist/js/npm.js
vendored
@ -1,6 +1,5 @@
|
||||
// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
|
||||
require('../../js/util.js')
|
||||
require('../../node_modules/mq4-hover-shim/dist/browser/mq4-hover-shim.js')
|
||||
require('../../js/alert.js')
|
||||
require('../../js/button.js')
|
||||
require('../../js/carousel.js')
|
||||
|
1
docs/dist/js/npm.js
vendored
1
docs/dist/js/npm.js
vendored
@ -10,4 +10,3 @@ require('../../js/tooltip.js')
|
||||
require('../../js/popover.js')
|
||||
require('../../js/scrollspy.js')
|
||||
require('../../js/tab.js')
|
||||
require('../../js/affix.js')
|
162
js/affix.js
162
js/affix.js
@ -1,162 +0,0 @@
|
||||
/* ========================================================================
|
||||
* Bootstrap: affix.js v3.3.2
|
||||
* http://getbootstrap.com/javascript/#affix
|
||||
* ========================================================================
|
||||
* Copyright 2011-2015 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
|
||||
+function ($) {
|
||||
'use strict';
|
||||
|
||||
// AFFIX CLASS DEFINITION
|
||||
// ======================
|
||||
|
||||
var Affix = function (element, options) {
|
||||
this.options = $.extend({}, Affix.DEFAULTS, options)
|
||||
|
||||
this.$target = $(this.options.target)
|
||||
.on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
|
||||
.on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
|
||||
|
||||
this.$element = $(element)
|
||||
this.affixed =
|
||||
this.unpin =
|
||||
this.pinnedOffset = null
|
||||
|
||||
this.checkPosition()
|
||||
}
|
||||
|
||||
Affix.VERSION = '3.3.2'
|
||||
|
||||
Affix.RESET = 'affix affix-top affix-bottom'
|
||||
|
||||
Affix.DEFAULTS = {
|
||||
offset: 0,
|
||||
target: window
|
||||
}
|
||||
|
||||
Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
|
||||
var scrollTop = this.$target.scrollTop()
|
||||
var position = this.$element.offset()
|
||||
var targetHeight = this.$target.height()
|
||||
|
||||
if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
|
||||
|
||||
if (this.affixed == 'bottom') {
|
||||
if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
|
||||
return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
|
||||
}
|
||||
|
||||
var initializing = this.affixed == null
|
||||
var colliderTop = initializing ? scrollTop : position.top
|
||||
var colliderHeight = initializing ? targetHeight : height
|
||||
|
||||
if (offsetTop != null && scrollTop <= offsetTop) return 'top'
|
||||
if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
Affix.prototype.getPinnedOffset = function () {
|
||||
if (this.pinnedOffset) return this.pinnedOffset
|
||||
this.$element.removeClass(Affix.RESET).addClass('affix')
|
||||
var scrollTop = this.$target.scrollTop()
|
||||
var position = this.$element.offset()
|
||||
return (this.pinnedOffset = position.top - scrollTop)
|
||||
}
|
||||
|
||||
Affix.prototype.checkPositionWithEventLoop = function () {
|
||||
setTimeout($.proxy(this.checkPosition, this), 1)
|
||||
}
|
||||
|
||||
Affix.prototype.checkPosition = function () {
|
||||
if (!this.$element.is(':visible')) return
|
||||
|
||||
var height = this.$element.height()
|
||||
var offset = this.options.offset
|
||||
var offsetTop = offset.top
|
||||
var offsetBottom = offset.bottom
|
||||
var scrollHeight = $('body').height()
|
||||
|
||||
if (typeof offset != 'object') offsetBottom = offsetTop = offset
|
||||
if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
|
||||
if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
|
||||
|
||||
var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
|
||||
|
||||
if (this.affixed != affix) {
|
||||
if (this.unpin != null) this.$element.css('top', '')
|
||||
|
||||
var affixType = 'affix' + (affix ? '-' + affix : '')
|
||||
var e = $.Event(affixType + '.bs.affix')
|
||||
|
||||
this.$element.trigger(e)
|
||||
|
||||
if (e.isDefaultPrevented()) return
|
||||
|
||||
this.affixed = affix
|
||||
this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
|
||||
|
||||
this.$element
|
||||
.removeClass(Affix.RESET)
|
||||
.addClass(affixType)
|
||||
.trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
|
||||
}
|
||||
|
||||
if (affix == 'bottom') {
|
||||
this.$element.offset({
|
||||
top: scrollHeight - height - offsetBottom
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// AFFIX PLUGIN DEFINITION
|
||||
// =======================
|
||||
|
||||
function Plugin(option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('bs.affix')
|
||||
var options = typeof option == 'object' && option
|
||||
|
||||
if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
|
||||
if (typeof option == 'string') data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
var old = $.fn.affix
|
||||
|
||||
$.fn.affix = Plugin
|
||||
$.fn.affix.Constructor = Affix
|
||||
|
||||
|
||||
// AFFIX NO CONFLICT
|
||||
// =================
|
||||
|
||||
$.fn.affix.noConflict = function () {
|
||||
$.fn.affix = old
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
// AFFIX DATA-API
|
||||
// ==============
|
||||
|
||||
$(window).on('load', function () {
|
||||
$('[data-spy="affix"]').each(function () {
|
||||
var $spy = $(this)
|
||||
var data = $spy.data()
|
||||
|
||||
data.offset = data.offset || {}
|
||||
|
||||
if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
|
||||
if (data.offsetTop != null) data.offset.top = data.offsetTop
|
||||
|
||||
Plugin.call($spy, data)
|
||||
})
|
||||
})
|
||||
|
||||
}(jQuery);
|
@ -1,101 +0,0 @@
|
||||
$(function () {
|
||||
'use strict';
|
||||
|
||||
module('affix plugin')
|
||||
|
||||
test('should be defined on jquery object', function () {
|
||||
ok($(document.body).affix, 'affix method is defined')
|
||||
})
|
||||
|
||||
module('affix', {
|
||||
setup: function () {
|
||||
// Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
|
||||
$.fn.bootstrapAffix = $.fn.affix.noConflict()
|
||||
},
|
||||
teardown: function () {
|
||||
$.fn.affix = $.fn.bootstrapAffix
|
||||
delete $.fn.bootstrapAffix
|
||||
}
|
||||
})
|
||||
|
||||
test('should provide no conflict', function () {
|
||||
strictEqual($.fn.affix, undefined, 'affix was set back to undefined (org value)')
|
||||
})
|
||||
|
||||
test('should return jquery collection containing the element', function () {
|
||||
var $el = $('<div/>')
|
||||
var $affix = $el.bootstrapAffix()
|
||||
ok($affix instanceof $, 'returns jquery collection')
|
||||
strictEqual($affix[0], $el[0], 'collection contains element')
|
||||
})
|
||||
|
||||
test('should exit early if element is not visible', function () {
|
||||
var $affix = $('<div style="display: none"/>').bootstrapAffix()
|
||||
$affix.data('bs.affix').checkPosition()
|
||||
ok(!$affix.hasClass('affix'), 'affix class was not added')
|
||||
})
|
||||
|
||||
test('should trigger affixed event after affix', function (assert) {
|
||||
var done = assert.async()
|
||||
|
||||
var templateHTML = '<div id="affixTarget">'
|
||||
+ '<ul>'
|
||||
+ '<li>Please affix</li>'
|
||||
+ '<li>And unaffix</li>'
|
||||
+ '</ul>'
|
||||
+ '</div>'
|
||||
+ '<div id="affixAfter" style="height: 20000px; display: block;"/>'
|
||||
$(templateHTML).appendTo(document.body)
|
||||
|
||||
$('#affixTarget').bootstrapAffix({
|
||||
offset: $('#affixTarget ul').position()
|
||||
})
|
||||
|
||||
$('#affixTarget')
|
||||
.on('affix.bs.affix', function () {
|
||||
ok(true, 'affix event fired')
|
||||
}).on('affixed.bs.affix', function () {
|
||||
ok(true, 'affixed event fired')
|
||||
$('#affixTarget, #affixAfter').remove()
|
||||
done()
|
||||
})
|
||||
|
||||
setTimeout(function () {
|
||||
window.scrollTo(0, document.body.scrollHeight)
|
||||
|
||||
setTimeout(function () {
|
||||
window.scroll(0, 0)
|
||||
}, 16) // for testing in a browser
|
||||
}, 0)
|
||||
})
|
||||
|
||||
test('should affix-top when scrolling up to offset when parent has padding', function (assert) {
|
||||
var done = assert.async()
|
||||
|
||||
var templateHTML = '<div id="padding-offset" style="padding-top: 20px;">'
|
||||
+ '<div id="affixTopTarget">'
|
||||
+ '<p>Testing affix-top class is added</p>'
|
||||
+ '</div>'
|
||||
+ '<div style="height: 1000px; display: block;"/>'
|
||||
+ '</div>'
|
||||
$(templateHTML).appendTo(document.body)
|
||||
|
||||
$('#affixTopTarget')
|
||||
.bootstrapAffix({
|
||||
offset: { top: 120, bottom: 0 }
|
||||
})
|
||||
.on('affixed-top.bs.affix', function () {
|
||||
ok($('#affixTopTarget').hasClass('affix-top'), 'affix-top class applied')
|
||||
$('#padding-offset').remove()
|
||||
done()
|
||||
})
|
||||
|
||||
setTimeout(function () {
|
||||
window.scrollTo(0, document.body.scrollHeight)
|
||||
|
||||
setTimeout(function () {
|
||||
window.scroll(0, 119)
|
||||
}, 250)
|
||||
}, 250)
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue
Block a user