vuikit
Version:
A responsive Vue UI library for web site interfaces based on UIkit
239 lines (233 loc) • 6.82 kB
JavaScript
/**
* Vuikit 0.8.10
* (c) 2018 Miljan Aleksic
* @license MIT
**/
/* Substantial part of the code is adapted from UIkit,
Copyright (c) 2013-2018 YOOtheme GmbH, getuikit.com */
import { $$, $ } from './util/core';
import { css } from './util/style';
import { data } from './util/attr';
import { warn } from './util/debug';
import { filter } from './util/filter';
import { trigger } from './util/event';
import { isInView, height, offset } from './util/dimensions';
import { filterOutTextNodes } from './util/vue';
import { addClass, removeClass, toggleClass } from './util/class';
import MixinEvents from './mixins/events';
import MixinFastdom from './mixins/fastdom';
import { closest } from './util/selector';
var scrollspy = {
name: 'VkScrollspy',
abstract: true,
mixins: [MixinEvents, MixinFastdom],
props: {
cls: {
type: Array,
default: function () { return []; }
},
target: {
default: false
},
hidden: {
type: Boolean,
default: true
},
offsetTop: {
type: Number,
default: 0
},
offsetLeft: {
type: Number,
default: 0
},
repeat: {
type: Boolean,
default: false
},
delay: {
type: Number,
default: 0
}
},
classMapping: {
inViewClass: 'uk-scrollspy-inview'
},
computed: {
elements: function elements () {
return this.target ? $$(this.target, this.$el) : [ this.$el ]
}
},
fastdom: [
{
write: function write () {
var ref = this.$options.classMapping;
var inViewClass = ref.inViewClass;
if (this.hidden) {
css(filter(this.elements, (":not(." + inViewClass + ")")), 'visibility', 'hidden');
}
}
},
{
read: function read (els) {
var this$1 = this;
this.elements.forEach(function (el, i) {
var elData = els[i];
if (!elData || elData.el !== el) {
var cls = data(el, 'vk-scrollspy-class');
elData = {el: el, toggles: cls && cls.split(',') || this$1.cls};
}
elData.show = isInView(el, this$1.offsetTop, this$1.offsetLeft);
els[i] = elData;
});
},
write: function write (els) {
var this$1 = this;
var ref = this.$options.classMapping;
var inViewClass = ref.inViewClass;
var index = this.elements.length === 1 ? 1 : 0;
this.elements.forEach(function (el, i) {
var elData = els[i];
var cls = elData.toggles[i] || elData.toggles[0];
if (elData.show && !elData.inview && !elData.timer) {
var show = function () {
css(el, 'visibility', '');
addClass(el, inViewClass);
toggleClass(el, cls);
trigger(el, 'inview');
this$1.fastdomUpdate();
elData.inview = true;
delete elData.timer;
};
if (this$1.delay && index) {
elData.timer = setTimeout(show, this$1.delay * index);
} else {
show();
}
index++;
} else if (!elData.show && elData.inview && this$1.repeat) {
if (elData.timer) {
clearTimeout(elData.timer);
delete elData.timer;
}
css(el, 'visibility', this$1.hidden ? 'hidden' : '');
removeClass(el, inViewClass);
toggleClass(el, cls);
trigger(el, 'outview');
this$1.fastdomUpdate();
elData.inview = false;
}
});
},
events: ['scroll', 'load', 'resize']
}
],
render: function render (h) {
var children = this.$slots.default;
if (!children) {
return
}
children = filterOutTextNodes(children);
if (!children.length) {
return
}
if (process.env.NODE_ENV !== 'production' && children.length > 1) {
warn('vk-scrollspy can only be used on a single element', this.$parent);
}
return children[0]
}
}
var scrollspyNav = {
name: 'VkScrollspyNav',
abstract: true,
mixins: [MixinEvents, MixinFastdom],
props: {
cls: {
type: String,
default: 'uk-active'
},
closest: {
type: String,
default: ''
},
overflow: {
type: Boolean,
default: true
},
offset: {
type: Number,
default: 0
}
},
methods: {
setComputed: function setComputed () {
this.links = $$('a[href^="#"]', this.$el).filter(function (el) { return el.hash; });
this.elements = this.closest ? closest(this.links, this.closest) : this.links;
this.targets = $$(this.links.map(function (el) { return el.hash; }).join(','));
}
},
fastdom: [
{
read: function read (data$$1) {
var this$1 = this;
var scroll = window.pageYOffset + this.offset + 1;
var max = height(document) - height(window) + this.offset;
data$$1.active = false;
this.targets.every(function (el, i) {
var ref = offset(el);
var top = ref.top;
var last = i + 1 === this$1.targets.length;
if (!this$1.overflow && (i === 0 && top > scroll || last && top + el.offsetTop < scroll)) {
return false
}
if (!last && offset(this$1.targets[i + 1]).top <= scroll) {
return true
}
if (scroll >= max) {
for (var j = this$1.targets.length - 1; j > i; j--) {
if (isInView(this$1.targets[j])) {
el = this$1.targets[j];
break
}
}
}
return !(data$$1.active = $(filter(this$1.links, ("[href=\"#" + (el.id) + "\"]"))))
});
},
write: function write (ref) {
var active = ref.active;
this.links.forEach(function (el) { return el.blur(); });
removeClass(this.elements, this.cls);
if (active) {
trigger(this.$el, 'active', [active, addClass(this.closest ? closest(active, this.closest) : active, this.cls)]);
}
},
events: ['scroll', 'load', 'resize']
}
],
mounted: function mounted () {
this.setComputed();
},
updated: function updated () {
var this$1 = this;
this.$nextTick(function () {
this$1.setComputed();
this$1.fastdomUpdate();
});
},
render: function render (h) {
var children = this.$slots.default;
if (!children) {
return
}
children = filterOutTextNodes(children);
if (!children.length) {
return
}
if (process.env.NODE_ENV !== 'production' && children.length > 1) {
warn('vk-scrollspy can only be used on a single element', this.$parent);
}
return children[0]
}
}
export { scrollspy as Scrollspy, scrollspyNav as ScrollspyNav };