organism-react-scroll-nav
Version:
A React scroll spy library with flux
318 lines • 10 kB
JavaScript
import _objectSpread from "reshow-runtime/es/helpers/objectSpread2";
import _classCallCheck from "reshow-runtime/es/helpers/classCallCheck";
import _createClass from "reshow-runtime/es/helpers/createClass";
import _defineProperty from "reshow-runtime/es/helpers/defineProperty";
import { mergeMap, Set, Map, ImmutableStore } from "reshow-flux";
import getScrollInfo from "get-scroll-info";
import { isOnScreen } from "get-window-offset";
import _getOffset from "getoffset";
import get from "get-object-value";
import callfunc, { debounce } from "call-func";
import { win } from "win-doc";
import query from "css-query-selector";
import testForPassiveScroll from "../testForPassiveScroll.mjs";
var incNum = 0;
var DEFAULT_SCROLL_ID = -1;
var Scroller = /*#__PURE__*/function () {
function Scroller() {
_classCallCheck(this, Scroller);
_defineProperty(this, "storeName", "delayScroll");
_defineProperty(this, "isInitResizeEvent", false);
_defineProperty(this, "checkIsActive", function (scrollTop, pos) {
return scrollTop >= pos.top - 1 && scrollTop <= pos.bottom - 2;
});
}
return _createClass(Scroller, [{
key: "initResizeEvent",
value: function initResizeEvent() {
var oWin = win();
if (!oWin.__null) {
this.isInitResizeEvent = true;
if (oWin.addEventListener) {
oWin.addEventListener("resize", this.bindHandleResize);
} else {
oWin.attachEvent("onresize", this.bindHandleResize);
}
}
}
}, {
key: "initEvent",
value: function initEvent(el, retry) {
var _this = this;
if ("undefined" !== typeof el) {
if (el.addEventListener) {
var supportsPassive = testForPassiveScroll();
el.addEventListener("scroll", this.scrollMonitor, supportsPassive ? {
passive: true
} : false);
} else {
el.attachEvent("onscroll", this.scrollMonitor);
}
var i = 0;
this.clearInitTimer();
this.initTimer = setInterval(
//for lazy content
function () {
_this.trigger(el);
i++;
if (i > retry) {
_this.clearInitTimer();
}
}, 300);
if (!this.isInitResizeEvent) {
this.initResizeEvent();
}
}
}
}, {
key: "removeEvent",
value: function removeEvent(el) {
if (el !== null && el !== void 0 && el.removeEventListener) {
el.removeEventListener("scroll", this.scrollMonitor);
} else {
el === null || el === void 0 || el.deachEvent("onscroll", this.scrollMonitor);
}
}
}, {
key: "handleResize",
value: function handleResize() {
var _this2 = this;
this.spys.keySeq().forEach(function (scrollId) {
_this2.scrollMonitor({
target: {
id: scrollId
}
});
});
}
}, {
key: "runScrollMonitor",
value: function runScrollMonitor(e) {
var delay = this.store.getState().get("scrollDelay");
this.scrollDebounce({
delay,
args: [e === null || e === void 0 ? void 0 : e.target]
});
}
}, {
key: "triggerScroll",
value: function triggerScroll(scrollNode) {
var _this3 = this;
var scrollId = get(scrollNode, ["id"]) || DEFAULT_SCROLL_ID;
var defaultMargin = this.store.getState().get("scrollMargin");
var actives = {
mdefault: null
};
var offsetCache = {};
var allMonitorNode = [];
var scroll = getScrollInfo();
var scrollTop = scroll.top + defaultMargin;
(this.spys.get(scrollId) || []).forEach(function (node) {
var nodeEl = node.getOffsetEl();
if (!nodeEl) {
return;
}
var nodeId = _this3.getNodeId(node);
var monitorScroll = callfunc(node.getMonitorScroll);
var scrollMargin = callfunc(node.getScrollMargin);
var pos = _getOffset(nodeEl);
if (monitorScroll) {
var isActive = _this3.checkIsActive(scrollTop, pos);
if (isActive) {
actives.mdefault = nodeId;
}
allMonitorNode.unshift(node);
}
var margin = scrollMargin ? scrollMargin : defaultMargin;
pos = isOnScreen(pos, scroll, margin);
offsetCache[nodeId] = pos;
});
var allMonitorNodeLen = allMonitorNode.length;
this.margins.forEach(function (margin) {
var scrollTop = scroll.top + margin;
actives["m" + margin] = null;
var i = allMonitorNodeLen;
while (i--) {
var node = allMonitorNode[i];
var nodeId = _this3.getNodeId(node);
var pos = offsetCache[nodeId];
var isActive = _this3.checkIsActive(scrollTop, pos);
if (isActive) {
actives["m" + margin] = nodeId;
break;
}
}
});
this.margins = this.margins.clear();
this.dispatch(_objectSpread(_objectSpread({}, actives), {}, {
offsetCache,
scroll,
storeName: this.storeName
}));
}
}, {
key: "getOffset",
value: function getOffset(id) {
var offset = get(this.store.getMap("offsetCache"), [id]);
if (offset && offset.h && offset.w) {
return offset;
} else {
var node = this.getNode(id) || {};
var dom = callfunc(node.getOffsetEl) || query.one("#" + id);
var domOffset = dom && _getOffset(dom);
if (domOffset) {
var scrollInfo = getScrollInfo();
var defaultMargin = this.store.getState().get("scrollMargin");
var margin = callfunc(node.getScrollMargin) || defaultMargin;
domOffset = isOnScreen(domOffset, scrollInfo, margin);
return domOffset;
} else {
return offset;
}
}
}
}, {
key: "hasAttach",
value: function hasAttach(node) {
var attachDestId = this.getAttachDestId(node);
var attachDest = this.spys.get(attachDestId);
if (attachDest && attachDest.has(node)) {
return attachDestId;
} else {
return false;
}
}
}, {
key: "getNodeId",
value: function getNodeId(node) {
var id = callfunc(node.getId) || node.id;
if (!id) {
if (node === win()) {
return DEFAULT_SCROLL_ID;
} else {
return this.setNodeId(node);
}
} else {
return id;
}
}
}, {
key: "setNodeId",
value: function setNodeId(node) {
var nextId = "spy-" + incNum;
incNum++;
if (node.setId) {
node.setId(nextId);
} else {
node.id = nextId;
}
return nextId;
}
}, {
key: "getAttachDestId",
value: function getAttachDestId(node) {
var attachDest = callfunc(node.getAttachDest);
var attachDestId;
if (attachDest) {
attachDestId = this.getNodeId(attachDest);
} else {
var oWin = win();
if (!oWin.__null) {
node.setAttachDest(oWin);
}
attachDestId = DEFAULT_SCROLL_ID;
}
return attachDestId;
}
}, {
key: "getNode",
value: function getNode(nodeId) {
var node = this.arrNode.get(nodeId);
return node;
}
}, {
key: "attach",
value: function attach(node) {
var nodeId = this.getNodeId(node);
/**
* if not set attachDest, the default attachDest is window.
*/
var attachDestId = this.getAttachDestId(node);
var attachDest = this.spys.get(attachDestId);
if (!attachDest) {
this.spys = this.spys.set(attachDestId, Set().add(node));
} else {
this.spys = this.spys.set(attachDestId, attachDest.add(node));
}
this.arrNode = this.arrNode.set(nodeId, node);
if (!this.isInitEvent.get(attachDestId)) {
this.isInitEvent = this.isInitEvent.set(attachDestId, true);
this.initEvent(callfunc(node.getAttachDest), callfunc(node.getAttachDestRetry));
}
return nodeId;
}
}, {
key: "detach",
value: function detach(node) {
var attachDestId = this.hasAttach(node);
if (attachDestId) {
this.spys = this.spys.set(attachDestId, this.spys.get(attachDestId).remove(node));
this.arrNode = this.arrNode.delete(this.getNodeId(node));
if (!this.spys.get(attachDestId).size) {
this.removeEvent(node.attachDestId);
this.spys = this.spys.delete(attachDestId);
this.isInitEvent = this.isInitEvent.delete(attachDestId);
}
}
}
}, {
key: "addMargin",
value: function addMargin(num) {
this.margins = this.margins.add(num);
}
}, {
key: "deleteMargin",
value: function deleteMargin(num) {
this.margins = this.margins.remove(num);
}
}, {
key: "clearInitTimer",
value: function clearInitTimer() {
if (this.initTimer) {
clearInterval(this.initTimer);
this.initTimer = null;
}
}
}, {
key: "getInitialState",
value: function getInitialState() {
this.initTimer = null;
this.trigger = this.triggerScroll.bind(this);
this.isInitEvent = Map();
this.spys = Map();
this.arrNode = Map();
this.margins = Set();
this.scrollMonitor = this.runScrollMonitor.bind(this);
this.scrollDebounce = debounce(this.trigger);
this.bindHandleResize = this.handleResize.bind(this);
return Map({
scrollDelay: 50,
scrollMargin: 0
});
}
}, {
key: "reduce",
value: function reduce(state, action) {
return mergeMap(state, action);
}
}]);
}();
var oDelayScroller = new Scroller();
var [store, delayScrollDispatch] = ImmutableStore(oDelayScroller.reduce.bind(oDelayScroller), oDelayScroller.getInitialState.bind(oDelayScroller));
var scrollStore = _objectSpread(_objectSpread({}, store), {}, {
scroller: oDelayScroller
});
oDelayScroller.dispatch = delayScrollDispatch;
oDelayScroller.store = store;
export default scrollStore;
export { Scroller };