Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

dom-align

Package Overview
Dependencies
Maintainers
1
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dom-align - npm Package Compare versions

Comparing version 0.0.1 to 1.0.0

lib/utils.js

54

examples/index.md
# dom-align@1.x
source: <select id='source_align_tb'>
<option value='t'>t</option>
<option value='c'>c</option>
<option value='b'>b</option>
</select> <select id='source_align_lr'>
<option value='l'>l</option>
<option value='c'>c</option>
<option value='r'>r</option>
</select>
target: <select id='target_align_tb'>
<option value='t'>t</option>
<option value='c'>c</option>
<option value='b'>b</option>
</select> <select id='target_align_lr'>
<option value='l'>l</option>
<option value='c'>c</option>
<option value='r'>r</option>
</select>
offset: [ <input type='offset' id='offset1' value='0' size=2/>, <input type='offset' id='offset2' value='0' size=2/> ]
overflow: <label>adjustX: <input type='checkbox' id='adjustX'/></label> <label>adjustY: <input type='checkbox' id='adjustY'/></label>
<button id='align'>align</button>
<br>
````html
<div style='width:180px;height:180px;overflow:auto;border:1px solid green;'>
<div style='background:yellow;width:100px;height:100px;margin:100px;' id='target'>
target node
</div>
<div style='background:red;width:50px;height:50px;position:absolute;top:-9999px;left:-9999px;position:relative;' id='source'>
</div>
</div>
````
<script>
function selectVal(sel){
sel = document.getElementById(sel);
return sel.value;
}
</script>
````js
var domAlign = require('../');
document.getElementById('align').onclick = function(){
domAlign(document.getElementById('source'),document.getElementById('target'),{
points: [selectVal('source_align_tb')+selectVal('source_align_lr'), selectVal('target_align_tb')+selectVal('target_align_lr')],
offset: [parseInt(document.getElementById('offset1').value), parseInt(document.getElementById('offset2').value)],
overflow: {
adjustX: document.getElementById('adjustX').checked,
adjustY: document.getElementById('adjustY').checked
}
});
};
````

@@ -1,1 +0,369 @@

module.exports = require('./lib/My-lib');
/**
* align dom node flexibly
* @author yiminghe@gmail.com
*/
var utils = require('./lib/utils');
// http://yiminghe.iteye.com/blog/1124720
/**
* 得到会导致元素显示不全的祖先元素
*/
function getOffsetParent(element) {
// ie 这个也不是完全可行
/*
<div style="width: 50px;height: 100px;overflow: hidden">
<div style="width: 50px;height: 100px;position: relative;" id="d6">
元素 6 高 100px 宽 50px<br/>
</div>
</div>
*/
// element.offsetParent does the right thing in ie7 and below. Return parent with layout!
// In other browsers it only includes elements with position absolute, relative or
// fixed, not elements with overflow set to auto or scroll.
// if (UA.ie && ieMode < 8) {
// return element.offsetParent;
// }
// 统一的 offsetParent 方法
var doc = element.ownerDocument,
body = doc.body,
parent,
positionStyle = utils.css(element, 'position'),
skipStatic = positionStyle === 'fixed' || positionStyle === 'absolute';
if (!skipStatic) {
return element.nodeName.toLowerCase() === 'html' ? null : element.parentNode;
}
for (parent = element.parentNode; parent && parent !== body; parent = parent.parentNode) {
positionStyle = utils.css(parent, 'position');
if (positionStyle !== 'static') {
return parent;
}
}
return null;
}
/**
* 获得元素的显示部分的区域
*/
function getVisibleRectForElement(element) {
var visibleRect = {
left: 0,
right: Infinity,
top: 0,
bottom: Infinity
},
el,
scrollX,
scrollY,
winSize,
doc = element.ownerDocument,
win = doc.defaultView || doc.parentWindow,
body = doc.body,
documentElement = doc.documentElement;
// Determine the size of the visible rect by climbing the dom accounting for
// all scrollable containers.
for (el = element;
(el = getOffsetParent(el));) {
// clientWidth is zero for inline block elements in ie.
if ((navigator.userAgent.indexOf('MSIE') === -1 || el.clientWidth !== 0) &&
// body may have overflow set on it, yet we still get the entire
// viewport. In some browsers, el.offsetParent may be
// document.documentElement, so check for that too.
(el !== body &&
el !== documentElement &&
utils.css(el, 'overflow') !== 'visible')) {
var pos = utils.offset(el);
// add border
pos.left += el.clientLeft;
pos.top += el.clientTop;
visibleRect.top = Math.max(visibleRect.top, pos.top);
visibleRect.right = Math.min(visibleRect.right,
// consider area without scrollBar
pos.left + el.clientWidth);
visibleRect.bottom = Math.min(visibleRect.bottom,
pos.top + el.clientHeight);
visibleRect.left = Math.max(visibleRect.left, pos.left);
}
}
// Clip by window's viewport.
scrollX = utils.getWindowScrollLeft(win);
scrollY = utils.getWindowScrollTop(win);
visibleRect.left = Math.max(visibleRect.left, scrollX);
visibleRect.top = Math.max(visibleRect.top, scrollY);
winSize = {
width: utils.viewportWidth(win),
height: utils.viewportHeight(win)
};
visibleRect.right = Math.min(visibleRect.right, scrollX + winSize.width);
visibleRect.bottom = Math.min(visibleRect.bottom, scrollY + winSize.height);
return visibleRect.top >= 0 && visibleRect.left >= 0 &&
visibleRect.bottom > visibleRect.top &&
visibleRect.right > visibleRect.left ?
visibleRect : null;
}
function getElFuturePos(elRegion, refNodeRegion, points, offset) {
var xy,
diff,
p1,
p2;
xy = {
left: elRegion.left,
top: elRegion.top
};
p1 = getAlignOffset(refNodeRegion, points[1]);
p2 = getAlignOffset(elRegion, points[0]);
diff = [p2.left - p1.left, p2.top - p1.top];
return {
left: xy.left - diff[0] + (+offset[0]),
top: xy.top - diff[1] + (+offset[1])
};
}
function isFailX(elFuturePos, elRegion, visibleRect) {
return elFuturePos.left < visibleRect.left ||
elFuturePos.left + elRegion.width > visibleRect.right;
}
function isFailY(elFuturePos, elRegion, visibleRect) {
return elFuturePos.top < visibleRect.top ||
elFuturePos.top + elRegion.height > visibleRect.bottom;
}
function adjustForViewport(elFuturePos, elRegion, visibleRect, overflow) {
var pos = utils.clone(elFuturePos),
size = {
width: elRegion.width,
height: elRegion.height
};
if (overflow.adjustX && pos.left < visibleRect.left) {
pos.left = visibleRect.left;
}
// Left edge inside and right edge outside viewport, try to resize it.
if (overflow.resizeWidth &&
pos.left >= visibleRect.left &&
pos.left + size.width > visibleRect.right) {
size.width -= (pos.left + size.width) - visibleRect.right;
}
// Right edge outside viewport, try to move it.
if (overflow.adjustX && pos.left + size.width > visibleRect.right) {
// 保证左边界和可视区域左边界对齐
pos.left = Math.max(visibleRect.right - size.width, visibleRect.left);
}
// Top edge outside viewport, try to move it.
if (overflow.adjustY && pos.top < visibleRect.top) {
pos.top = visibleRect.top;
}
// Top edge inside and bottom edge outside viewport, try to resize it.
if (overflow.resizeHeight &&
pos.top >= visibleRect.top &&
pos.top + size.height > visibleRect.bottom) {
size.height -= (pos.top + size.height) - visibleRect.bottom;
}
// Bottom edge outside viewport, try to move it.
if (overflow.adjustY && pos.top + size.height > visibleRect.bottom) {
// 保证上边界和可视区域上边界对齐
pos.top = Math.max(visibleRect.bottom - size.height, visibleRect.top);
}
return utils.mix(pos, size);
}
function flip(points, reg, map) {
var ret = [];
utils.each(points, function (p) {
ret.push(p.replace(reg, function (m) {
return map[m];
}));
});
return ret;
}
function flipOffset(offset, index) {
offset[index] = -offset[index];
return offset;
}
domAlign.__getOffsetParent = getOffsetParent;
domAlign.__getVisibleRectForElement = getVisibleRectForElement;
function getRegion(node) {
var offset, w, h;
if (!utils.isWindow(node)) {
offset = utils.offset(node);
w = utils.outerWidth(node);
h = utils.outerHeight(node);
} else {
var win = utils.getWindow(node);
offset = {
left: utils.getWindowScrollLeft(win),
top: utils.getWindowScrollTop(win)
};
w = utils.viewportWidth(win);
h = utils.viewportHeight(win);
}
offset.width = w;
offset.height = h;
return offset;
}
/**
* 获取 node 上的 align 对齐点 相对于页面的坐标
*/
function getAlignOffset(region, align) {
var V = align.charAt(0),
H = align.charAt(1),
w = region.width,
h = region.height,
x, y;
x = region.left;
y = region.top;
if (V === 'c') {
y += h / 2;
} else if (V === 'b') {
y += h;
}
if (H === 'c') {
x += w / 2;
} else if (H === 'r') {
x += w;
}
return {
left: x,
top: y
};
}
/*
* align node
* @param {Element} node current dom node
* @param {Object} align align config
*
* @example
* {
* node: null, // 参考元素, falsy 或 window 为可视区域, 'trigger' 为触发元素, 其他为指定元素
* points: ['cc','cc'], // ['tr', 'tl'] 表示 overlay 的 tr 与参考节点的 tl 对齐
* offset: [0, 0] // 有效值为 [n, m]
* }
*/
function domAlign(el, refNode, align) {
var points = align.points;
var offset = align.offset;
var overflow = align.overflow;
offset = offset && [].concat(offset) || [0, 0];
overflow = overflow || {};
var fail = 0;
// 当前节点可以被放置的显示区域
var visibleRect = getVisibleRectForElement(el);
// 当前节点所占的区域, left/top/width/height
var elRegion = getRegion(el);
// 参照节点所占的区域, left/top/width/height
var refNodeRegion = getRegion(refNode);
// 当前节点将要被放置的位置
var elFuturePos = getElFuturePos(elRegion, refNodeRegion, points, offset);
// 当前节点将要所处的区域
var newElRegion = utils.merge(elRegion, elFuturePos);
// 如果可视区域不能完全放置当前节点时允许调整
if (visibleRect && (overflow.adjustX || overflow.adjustY)) {
if(overflow.adjustX) {
// 如果横向不能放下
if (isFailX(elFuturePos, elRegion, visibleRect)) {
fail = 1;
// 对齐位置反下
points = flip(points, /[lr]/ig, {
l: 'r',
r: 'l'
});
// 偏移量也反下
offset = flipOffset(offset, 0);
}
}
if(overflow.adjustY) {
// 如果纵向不能放下
if (isFailY(elFuturePos, elRegion, visibleRect)) {
fail = 1;
// 对齐位置反下
points = flip(points, /[tb]/ig, {
t: 'b',
b: 't'
});
// 偏移量也反下
offset = flipOffset(offset, 1);
}
}
// 如果失败,重新计算当前节点将要被放置的位置
if (fail) {
elFuturePos = getElFuturePos(elRegion, refNodeRegion, points, offset);
utils.mix(newElRegion, elFuturePos);
}
var newOverflowCfg = {};
// 检查反下后的位置是否可以放下了
// 如果仍然放不下只有指定了可以调整当前方向才调整
newOverflowCfg.adjustX = overflow.adjustX &&
isFailX(elFuturePos, elRegion, visibleRect);
newOverflowCfg.adjustY = overflow.adjustY &&
isFailY(elFuturePos, elRegion, visibleRect);
// 确实要调整,甚至可能会调整高度宽度
if (newOverflowCfg.adjustX || newOverflowCfg.adjustY) {
newElRegion = adjustForViewport(elFuturePos, elRegion,
visibleRect, newOverflowCfg);
}
}
// https://github.com/kissyteam/kissy/issues/190
// http://localhost:8888/kissy/src/overlay/demo/other/relative_align/align.html
// 相对于屏幕位置没变,而 left/top 变了
// 例如 <div 'relative'><el absolute></div>
utils.offset(el, {left: newElRegion.left, top: newElRegion.top});
// need judge to in case set fixed with in css on height auto element
if (newElRegion.width !== elRegion.width) {
utils.css(el, 'width', el.width() + newElRegion.width - elRegion.width);
}
if (newElRegion.height !== elRegion.height) {
utils.css(el, 'height', el.height() + newElRegion.height - elRegion.height);
}
}
module.exports = domAlign;
/**
* 2012-04-26 yiminghe@gmail.com
* - 优化智能对齐算法
* - 慎用 resizeXX
*
* 2011-07-13 yiminghe@gmail.com note:
* - 增加智能对齐,以及大小调整选项
**/

11

package.json
{
"name": "dom-align",
"version": "0.0.1",
"version": "1.0.0",
"description": "Align DOM Node Flexibly ",

@@ -20,4 +20,4 @@ "keywords": [

"spm": {},
"config":{
"port":8000
"config": {
"port": 8000
},

@@ -36,7 +36,8 @@ "scripts": {

"devDependencies": {
"expect.js": "^0.3.1",
"jquery": "^1.11.2",
"modulex": "^1.7.4",
"precommit-hook": "^1.0.7",
"rc-server": "^1.5.4",
"rc-tools": "^1.1.3",
"expect.js": "~0.3.1",
"modulex": "^1.7.4",
"react": "~0.12.1"

@@ -43,0 +44,0 @@ },

# dom-align
react my-lib component
align source html element with target html element flexibly.
port from [kissyteam/component align](https://github.com/kissyteam/component/blob/master/lib/component/extension/align.js)

@@ -25,6 +26,20 @@ [![NPM version][npm-image]][npm-url]

## install
## Screenshot
<img height=444 src="http://gtms02.alicdn.com/tps/i2/TB1XIp2HXXXXXajaXXXgJfr8XXX-548-888.png">
## Install
[![dom-align](https://nodei.co/npm/dom-align.png)](https://npmjs.org/package/dom-align)
## Feature
* support ie6+ chrome firefox
* support align points and offset
* support auto adjust according to visible area
## Online Demo
* http://spmjs.io/docs/dom-align/examples/
## Usage

@@ -35,4 +50,47 @@

// use domAlign
// sourceNode's initial style should be position:absolute;left:-9999px;top:-9999px;
domAlign(sourceNode, targetNode, {
points: ['tl', 'tr'] // align top left point of sourceNode with top right point of targetNode
offset: [10, 20] // the offset sourceNode by 10px in x and 20px in y
});
```
## API
### void domAlign(source: HTMLElement, target: HTMLElement, alignConfig: Object):Function
#### alignConfig object details
<table class="table table-bordered table-striped">
<thead>
<tr>
<th style="width: 100px;">name</th>
<th style="width: 50px;">type</th>
<th>description</th>
</tr>
</thead>
<tbody>
<tr>
<td>points</td>
<td>String[2]</td>
<td>move point of source node to align with point of target node, such as ['tr','cc'],
align top right point of source node with center point of target node.
point can be 't'(top), 'b'(bottom), 'c'(center), 'l'(left), 'r'(right)
</td>
</tr>
<tr>
<td>offset</td>
<td>Number[2]</td>
<td>offset source node by offset[0] in x and offset[1] in y</td>
</tr>
<tr>
<td>overflow</td>
<td>Object</td>
<td>if adjustX field is true, then will adjust source node in x direction if source node is invisible.
if adjustY field is true, then will adjust source node in y direction if source node is invisible.
</td>
</tr>
</tbody>
</table>
## Development

@@ -39,0 +97,0 @@

@@ -1,5 +0,273 @@

/** @jsx React.DOM */
var domAlign = require('../');
var $ = require('jquery');
var expect = require('expect.js');
describe('dom-align', function (){
$('<style>html,body {padding:0;margin:0;border:none;}</style>').appendTo(document.getElementsByTagName('head'));
describe("dom-align", function () {
function toBeEqualRect(actual, expect) {
for (var i in actual) {
if (actual[i] - expect[i] < 5) {
} else {
return false;
}
}
return true;
}
it("unified getOffsetParent method", function () {
var getOffsetParent = domAlign.__getOffsetParent;
var test = [];
test[0] = "<div><div></div></div>";
test[1] = "<div><div style='position: relative;'></div></div>";
test[2] = "<div>" +
"<div>" +
"<div style='position: absolute;'></div>" +
"</div>" +
"</div>";
test[3] = "<div style='position: relative;'>" +
"<div>" +
"<div style='position: absolute;'></div>" +
"</div>" +
"</div>";
var dom = [];
for (var i = 0; i < 4; i++) {
dom[i] = $(test[i])[0];
document.body.appendChild(dom[i]);
}
expect(getOffsetParent(dom[0].firstChild)).to.be(dom[0]);
expect(getOffsetParent(dom[1].firstChild)).to.be(dom[1]);
expect(getOffsetParent(dom[2].firstChild.firstChild)).to.be(null);
expect(getOffsetParent(dom[3].firstChild.firstChild)).to.be(dom[3]);
for (i = 0; i < 4; i++) {
$(dom[i]).remove();
}
});
it("getVisibleRectForElement works", function (done) {
var gap = $("<div style='height: 1500px;width: 100000px;'></div>")[0];
document.body.appendChild(gap);
var getVisibleRectForElement = domAlign.__getVisibleRectForElement,
test = [];
test[0] = "<div><div></div></div>";
test[1] = "<div style='width: 100px;height: 100px;overflow: hidden;'>" +
"<div style='position: relative;'></div></div>";
test[2] = "<div style='width: 100px;height: 100px;overflow: hidden;'>" +
"<div>" +
"<div style='position: absolute;'></div>" +
"</div>" +
"</div>";
test[3] = "<div style='position: relative;width: 100px;" +
"height: 100px;overflow: hidden;'>" +
"<div>" +
"<div style='position: absolute;'></div>" +
"</div>" +
"</div>";
var dom = [];
for (var i = 3; i >= 0; i--) {
dom[i] = $(test[i])[0];
document.body.appendChild(dom[i]);
}
// 1
window.scrollTo(10, 10);
var right = 10 + $(window).width(),
rect,
bottom = 10 + $(window).height();
rect = getVisibleRectForElement(dom[0].firstChild);
expect(rect.left - 10).within(-10, 10);
expect(rect.top - 10).within(-10, 10);
expect(rect.right - right).within(-10, 10);
expect(rect.bottom - bottom).within(-10, 10);
window.scrollTo(200, 200);
rect = getVisibleRectForElement(dom[0].firstChild);
expect(rect.left).to.eql(200);
expect(rect.bottom).to.eql(200 + $(window).height());
expect(rect.top).to.eql(200);
expect(rect.right).to.eql(200 + $(window).width());
$(dom[0]).remove();
// 2
window.scrollTo(10, 10);
rect = getVisibleRectForElement(dom[1].firstChild);
expect(toBeEqualRect(rect, {
left: 10,
top: 10,
right: 100,
bottom: 100
})).to.be.ok();
window.scrollTo(200, 200);
rect = getVisibleRectForElement(dom[1].firstChild);
expect(rect).to.be(null);
$(dom[1]).remove();
// 3
window.scrollTo(10, 10);
rect = getVisibleRectForElement(dom[2].firstChild);
expect(toBeEqualRect(rect, {
left: 10,
top: 10,
right: 100,
bottom: 100
})).to.be.ok();
window.scrollTo(200, 200);
rect = getVisibleRectForElement(dom[2].firstChild);
expect(rect).to.be(null);
$(dom[2]).remove();
// 4
window.scrollTo(10, 10);
rect = getVisibleRectForElement(dom[3].firstChild);
expect(toBeEqualRect(rect, {
left: 10,
top: 10,
right: 100,
bottom: 100
})).to.be.ok();
window.scrollTo(200, 200);
rect = getVisibleRectForElement(dom[3].firstChild);
expect(rect).to.be(null);
$(dom[3]).remove();
$(gap).remove();
setTimeout(function () {
window.scrollTo(0, 0);
done();
}, 200);
});
describe("auto align", function () {
it("should not auto adjust if current position is right", function () {
var node;
node = $("<div style='position: absolute;left:0;top:0;" +
"width: 100px;height: 100px;" +
"overflow: hidden'>" +
"<div style='position: absolute;" +
"width: 50px;" +
"height: 50px;'>" +
"</div>" +
"<div style='position: absolute;left:0;top:20px;'></div>" +
"<div style='position: absolute;left:0;top:80px;'></div>" +
"</div>").appendTo('body');
var target = node.children().eq(0);
//upper = node.children().eq(1),
var lower = node.children().eq(2);
var containerOffset = node.offset();
var targetOffset = target.offset();
domAlign(target[0], lower[0], {points: ['bl', 'tl']});
var afterTargetOffset = target.offset();
// _____________
// | |
// |______ |
// | | |
// |______|______|
// |_____________|
expect(target.offset().left - containerOffset.left).within(-10, 10);
expect(target.offset().top - containerOffset.top - 30).within(-10, 10);
domAlign(target[0], lower[0], {
points: ['tl', 'bl'],
overflow: {
adjustX: 1,
adjustY: 1
}
});
// _____________
// | |
// |______ |
// | | |
// |______|______|
// |_____________|
// flip 然后 ok
containerOffset = node.offset();
expect(target.offset().left - containerOffset.left).within(-10, 10);
var actual = target.offset().top;
var expected = containerOffset.top + 30;
expect(actual - expected).within(-5, 5);
});
it('auto works 2', function () {
var node = $("<div style='position: absolute;left:100px;top:100px;" +
"width: 100px;height: 100px;" +
"overflow: hidden'>" +
"<div style='position: absolute;" +
"width: 50px;" +
"height: 90px;'>" +
"</div>" +
"<div style='position: absolute;left:0;top:20px;'></div>" +
"<div style='position: absolute;left:0;top:80px;'></div>" +
"</div>").appendTo('body');
var target = node.children().eq(0),
//upper = node.children().eq(1),
lower = node.children().eq(2);
var containerOffset = node.offset();
domAlign(target[0], lower[0], {points: ['bl', 'tl']});
// |------|
// | _____|________
// | | |
// | | |
// | | |
// |______|______|
// |_____________|
expect(target.offset().left - containerOffset.left).within(-5, 5);
expect(target.offset().top - (containerOffset.top - 10)).within(-5, 5);
domAlign(target[0], lower[0], {
points: ['tl', 'bl'],
overflow: {
adjustX: 1,
adjustY: 1
}
});
// _____________
// | | |
// |--- --| |
// | | |
// |______|______|
// | | |
// |______|______|
// flip 不 ok,对 flip 后的 adjustY 到视窗边界
expect(target.offset().left - containerOffset.left).within(-5, 5);
expect(target.offset().top - containerOffset.top).within(-5, 5);
});
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc