/** * @ignore * auto scroll for drag object's container * @author yiminghe@gmail.com */ KISSY.add('dd/plugin/scroll', function (S, DD, Base, Node, DOM) { var DDM = DD.DDM, win = S.Env.host, SCROLL_EVENT = '.-ks-dd-scroll' + S.now(), RATE = [10, 10], ADJUST_DELAY = 100, DIFF = [20, 20]; /** * @class KISSY.DD.Plugin.Scroll * Scroll plugin to make parent node scroll while dragging. */ function Scroll() { Scroll.superclass.constructor.apply(this, arguments); } Scroll.ATTRS = { /** * node to be scrolled while dragging * @cfg {window|String|HTMLElement} node */ /** * @ignore */ node: { // value:window:不行,默认值一定是简单对象 valueFn: function () { return Node.one(win); }, setter: function (v) { return Node.one(v); } }, /** * adjust velocity, larger faster * default [10,10] * @cfg {Number[]} rate */ /** * @ignore */ rate: { value: RATE }, /** * the margin to make node scroll, easier to scroll for node if larger. * default [20,20] * @cfg {number[]} diff */ /** * @ignore */ diff: { value: DIFF } }; var isWin = S.isWindow; S.extend(Scroll, Base, { pluginId: 'dd/plugin/scroll', /** * Get container node region. * @private */ getRegion: function (node) { if (isWin(node[0])) { return { width: DOM.viewportWidth(), height: DOM.viewportHeight() }; } else { return { width: node.outerWidth(), height: node.outerHeight() }; } }, /** * Get container node offset. * @private */ getOffset: function (node) { if (isWin(node[0])) { return { left: DOM.scrollLeft(), top: DOM.scrollTop() }; } else { return node.offset(); } }, /** * Get container node scroll. * @private */ getScroll: function (node) { return { left: node.scrollLeft(), top: node.scrollTop() }; }, /** * scroll container node. * @private */ setScroll: function (node, r) { node.scrollLeft(r.left); node.scrollTop(r.top); }, /** * make node not to scroll while this drag object is dragging * @param {KISSY.DD.Draggable} drag * @private */ pluginDestructor: function (drag) { drag['detach'](SCROLL_EVENT); }, /** * make node to scroll while this drag object is dragging * @param {KISSY.DD.Draggable} drag * @private */ pluginInitializer: function (drag) { var self = this, node = self.get('node'); var rate = self.get('rate'), diff = self.get('diff'), event, // 目前相对 container 的偏移,container 为 window 时,相对于 viewport dxy, timer = null; // fix https://github.com/kissyteam/kissy/issues/115 // dragDelegate 时 可能一个 dragDelegate对应多个 scroll // check container function checkContainer() { if (isWin(node[0])) { return 0; } // 判断 proxyNode,不对 dragNode 做大的改变 var mousePos = drag.mousePos, r = DDM.region(node); if (!DDM.inRegion(r, mousePos)) { clearTimeout(timer); timer = 0; return 1; } return 0; } function dragging(ev) { // 给调用者的事件,框架不需要处理 // fake 也表示该事件不是因为 mouseover 产生的 if (ev.fake) { return; } if (checkContainer()) { return; } // 更新当前鼠标相对于拖节点的相对位置 event = ev; dxy = S.clone(drag.mousePos); var offset = self.getOffset(node); dxy.left -= offset.left; dxy.top -= offset.top; if (!timer) { checkAndScroll(); } } function dragEnd() { clearTimeout(timer); timer = null; } drag.on('drag' + SCROLL_EVENT, dragging); drag.on('dragstart' + SCROLL_EVENT, function () { DDM.cacheWH(node); }); drag.on('dragend' + SCROLL_EVENT, dragEnd); function checkAndScroll() { if (checkContainer()) { return; } var r = self.getRegion(node), nw = r.width, nh = r.height, scroll = self.getScroll(node), origin = S.clone(scroll), diffY = dxy.top - nh, adjust = false; if (diffY >= -diff[1]) { scroll.top += rate[1]; adjust = true; } var diffY2 = dxy.top; if (diffY2 <= diff[1]) { scroll.top -= rate[1]; adjust = true; } var diffX = dxy.left - nw; if (diffX >= -diff[0]) { scroll.left += rate[0]; adjust = true; } var diffX2 = dxy.left; if (diffX2 <= diff[0]) { scroll.left -= rate[0]; adjust = true; } if (adjust) { self.setScroll(node, scroll); timer = setTimeout(checkAndScroll, ADJUST_DELAY); // 不希望更新相对值,特别对于相对 window 时,相对值如果不真正拖放触发的 drag,是不变的, // 不会因为程序 scroll 而改变相对值 // 调整事件,不需要 scroll 监控,达到预期结果:元素随容器的持续不断滚动而自动调整位置. event.fake = true; if (isWin(node[0])) { // 当使 window 自动滚动时,也要使得拖放物体相对文档位置随 scroll 改变 // 而相对 node 容器时,只需 node 容器滚动,拖动物体相对文档位置不需要改变 scroll = self.getScroll(node); event.left += scroll.left - origin.left; event.top += scroll.top - origin.top; } // 容器滚动了,元素也要重新设置 left,top if (drag.get('move')) { drag.get('node').offset(event); } drag.fire('drag', event); } else { timer = null; } } } }); return Scroll; }, { requires: ['dd/base', 'base', 'node', 'dom'] });