define(function(require, exports, module) { "use strict"; var Util = require('../util'); var Base = require('../base'); //transform var transform = Util.prefixStyle("transform"); // default render function for position:sticky elements var defaultStickyRenderFunc = function(e) { var stickyElement = e.stickyElement; var curStickyElement = e.curStickyElement; var xscroll = e.xscroll; var _ = e._; var infinite = xscroll.getPlugin("infinite"); if (infinite) { infinite.userConfig.renderHook.call(self, stickyElement, curStickyElement); stickyElement.setAttribute("xs-guid", curStickyElement.guid); Util.addClass(stickyElement, curStickyElement.className); for (var attrName in curStickyElement.style) { if (attrName != "display" && attrName != "position") { //copy styles stickyElement.style[attrName] = attrName == _.height ? curStickyElement.style[attrName] + 'px' : curStickyElement.style[attrName]; } } } else { var style = curStickyElement.getAttribute("style"); stickyElement.innerHTML = curStickyElement.innerHTML; stickyElement.className = curStickyElement.className; style && stickyElement.setAttribute("style", style); } } var Sticky = function(cfg) { Sticky.superclass.constructor.call(this, cfg); this.userConfig = Util.mix({ stickyRenderTo: undefined, forceSticky: true, prefix: "xs-sticky-container", stickyRenderFunc: defaultStickyRenderFunc, zoomType: "y" }, cfg); this.init(); } Util.extend(Sticky, Base, { init: function() { var self = this, userConfig = self.userConfig, xscroll = self.xscroll = userConfig.xscroll; var isY = self.isY = !!(userConfig.zoomType == "y"); self._ = { top: self.isY ? "top" : "left", left: self.isY ? "left" : "bottom", right: self.isY ? "right" : "top", height: self.isY ? "height" : "width", width: self.isY ? "width" : "height" }; self.stickyRenderTo = Util.getNode(userConfig.stickyRenderTo); self._handlers = []; return self; }, getStickiesPos: function() { var self = this; var xscroll = self.xscroll; var isInfinite = self.isInfinite; var isY = self.isY; var _ = self._; var stickiesPos = []; var getPos = function(sticky) { var pos = {}; if (isInfinite) { pos[_.top] = isY ? sticky._top : sticky._left; pos[_.height] = isY ? sticky._height : sticky._width; } else { pos[_.top] = self.isY ? Util.getOffsetTop(sticky) : Util.getOffsetLeft(sticky); pos[_.height] = self.isY ? sticky.offsetHeight : sticky.offsetWidth; } return pos; } for (var i = 0; i < self.stickiesNum; i++) { var pos = getPos(self.stickyElements[i]); self._handlers[i] = self._handlers[i] || self.createStickyEl(); pos.el = self._handlers[i]; pos.isRender = false; stickiesPos.push(pos); } return stickiesPos }, getStickyElements: function() { var self = this; var xscroll = self.xscroll; var userConfig = self.userConfig; var isInfinite = self.isInfinite; var infinite = xscroll.getPlugin("infinite"); if (infinite) { var stickyElements = [], serializedData = infinite.__serializedData; for (var i in serializedData) { var rowData = serializedData[i]; if (rowData && rowData.style && "sticky" == rowData.style.position) { stickyElements.push(rowData); } } return stickyElements; } else { return Util.getNodes(xscroll.userConfig.stickyElements, xscroll.content); } }, render: function(force) { var self = this; var userConfig = self.userConfig; var xscroll = self.xscroll; self.isInfinite = !!xscroll.getPlugin("infinite"); var _ = self._; self.stickyElements = self.getStickyElements(); self.stickiesNum = self.stickyElements && self.stickyElements.length; if (!self.stickiesNum) return; if (!self.stickyRenderTo) { self.stickyRenderTo = document.createElement('div'); xscroll.renderTo.appendChild(self.stickyRenderTo); } self.stickiesPos = self.getStickiesPos(); var stickyRenderTo = self.stickyRenderTo; stickyRenderTo.style[_.top] = 0; stickyRenderTo.style[_.left] = 0; stickyRenderTo.style[_.right] = 0; stickyRenderTo.style.position = xscroll.userConfig.useOriginScroll ? "fixed" : "absolute"; Util.addClass(self.stickyRenderTo, userConfig.prefix); self.stickyHandler(force); self._bindEvt(); }, createStickyEl: function() { var self = this; var el = document.createElement('div'); el.style.display = "none"; Util.addClass(el, "xs-sticky-handler"); self.stickyRenderTo.appendChild(el); return el; }, _bindEvt: function() { var self = this, xscroll = self.xscroll; xscroll.on("scroll", self.stickyHandler, self); }, stickyHandler: function(force) { var self = this; var xscroll = self.xscroll; var userConfig = self.userConfig; var scrollTop = self.isY ? xscroll.getScrollTop() : xscroll.getScrollLeft(); var stickiesPos = self.stickiesPos; var _ = self._; var indexes = []; for (var i = 0, l = stickiesPos.length; i < l; i++) { var top = stickiesPos[i][_.top]; if (scrollTop > top) { indexes.push(i); } } if (!indexes.length) { if (self.stickyElement) { self.stickyElement.style.display = "none"; } self.curStickyIndex = undefined; return; } var curStickyIndex = Math.max.apply(null, indexes); if (self.curStickyIndex != curStickyIndex || force) { var prevStickyIndex = self.curStickyIndex; self.curStickyIndex = curStickyIndex; self.curStickyElement = self.stickyElements[curStickyIndex]; self.curStickyPos = stickiesPos[curStickyIndex]; self.stickyElement = self.curStickyPos.el; for (var i = 0, l = stickiesPos.length; i < l; i++) { stickiesPos[i].el.style.display = "none"; } var eventsObj = { stickyElement: self.stickyElement, curStickyIndex: self.curStickyIndex, prevStickyIndex: prevStickyIndex, curStickyPos: self.curStickyPos, isRender: self.curStickyPos.isRender }; xscroll.trigger("beforestickychange", eventsObj); self._stickyRenderFunc(self); xscroll.trigger("stickychange", eventsObj); } var trans = 0; if (self.stickiesPos[self.curStickyIndex + 1]) { var cur = self.stickiesPos[self.curStickyIndex]; var next = self.stickiesPos[self.curStickyIndex + 1]; if (scrollTop + cur[_.height] > next[_.top] && scrollTop + cur[_.height] < next[_.top] + cur[_.height]) { trans = cur[_.height] + scrollTop - next[_.top]; } else { trans = 0; } } self.stickyElement.style[transform] = self.isY ? "translateY(-" + (trans) + "px) translateZ(0)" : "translateX(-" + (trans) + "px) translateZ(0)"; }, _stickyRenderFunc: function(e) { var self = this; var _ = self._; var stickyRenderFunc = self.userConfig.stickyRenderFunc; var el = self.curStickyPos.el; if (!self.curStickyPos.isRender) { el.style[_.left] = 0; el.style[_.right] = 0; stickyRenderFunc && stickyRenderFunc.call(self, e); } el.style.display = "block"; self.curStickyPos.isRender = true; }, destroy: function() { var self = this; self.stickyElements = undefined; self.stickiesNum = undefined; self.stickiesPos = undefined; Util.remove(self.stickyElement); self.stickyElement = undefined; } }); if (typeof module == 'object' && module.exports) { module.exports = Sticky; } /** ignored by jsdoc **/ else { return Sticky; } });