| 1436 | /** |
| 1437 | * Make any page element visible inside one of the ancestor by scrolling the parent. |
| 1438 | * @param {CKEDITOR.dom.element|CKEDITOR.dom.window} parent The container to scroll into. |
| 1439 | * @param {Boolean} [alignToTop] Align the element's top side with the container's |
| 1440 | * when "true" is specified, align the bottom with viewport bottom when "false" is specified, |
| 1441 | * other wise scroll on either side with the minimum amount to show the element. |
| 1442 | * @param {Boolean} [hscroll] Whether horizontal overflow should be considered. |
| 1443 | */ |
| 1444 | scrollIntoParent : function( parent, alignToTop, hscroll ) |
| 1445 | { |
| 1446 | !parent && ( parent = this.getWindow() ); |
| 1447 | |
| 1448 | var doc = parent.getDocument(); |
| 1449 | var isQuirks = doc.$.compatMode == 'BackCompat'; |
| 1450 | |
| 1451 | // On window <html> is scrolled while quirks scrolls <body>. |
| 1452 | if ( parent instanceof CKEDITOR.dom.window ) |
| 1453 | parent = isQuirks ? doc.getBody() : doc.getDocumentElement(); |
| 1454 | |
| 1455 | // Scroll the parent by the specified amount. |
| 1456 | function scrollBy( x, y ) |
| 1457 | { |
| 1458 | // Webkit doesn't support "scrollTop/scrollLeft" |
| 1459 | // on documentElement/body element. |
| 1460 | if ( /body|html/.test( parent.getName() ) ) |
| 1461 | parent.getWindow().$.scrollBy( x, y ); |
| 1462 | else |
| 1463 | { |
| 1464 | parent.$[ 'scrollLeft' ] += x; |
| 1465 | parent.$[ 'scrollTop' ] += y; |
| 1466 | } |
| 1467 | } |
| 1468 | |
| 1469 | // Figure out the element position relative to the specified window. |
| 1470 | function screenPos( element, refWin ) |
| 1471 | { |
| 1472 | var pos = { x: 0, y: 0 }; |
| 1473 | |
| 1474 | if ( !( element.is( isQuirks ? 'body' : 'html' ) ) ) |
| 1475 | { |
| 1476 | var box = element.$.getBoundingClientRect(); |
| 1477 | pos.x = box.left, pos.y = box.top; |
| 1478 | } |
| 1479 | |
| 1480 | var win = element.getWindow(); |
| 1481 | if ( !win.equals( refWin ) ) |
| 1482 | { |
| 1483 | var outerPos = screenPos( CKEDITOR.dom.element.get( win.$.frameElement ), refWin ); |
| 1484 | pos.x += outerPos.x, pos.y += outerPos.y; |
| 1485 | } |
| 1486 | |
| 1487 | return pos; |
| 1488 | } |
| 1489 | |
| 1490 | // calculated margin size. |
| 1491 | function margin( element, side ) |
| 1492 | { |
| 1493 | return parseInt( element.getComputedStyle( 'margin-' + side ) || 0, 10 ) || 0; |
| 1494 | } |
| 1495 | |
| 1496 | var win = parent.getWindow(); |
| 1497 | |
| 1498 | var thisPos = screenPos( this, win ), |
| 1499 | parentPos = screenPos( parent, win ), |
| 1500 | eh = this.$.offsetHeight, |
| 1501 | ew = this.$.offsetWidth, |
| 1502 | ch = parent.$.clientHeight, |
| 1503 | cw = parent.$.clientWidth, |
| 1504 | lt, |
| 1505 | br; |
| 1506 | |
| 1507 | // Left-top margins. |
| 1508 | lt = |
| 1509 | { |
| 1510 | x : thisPos.x - margin( this, 'left' ) - parentPos.x || 0, |
| 1511 | y : thisPos.y - margin( this, 'top' ) - parentPos.y|| 0 |
| 1512 | }; |
| 1513 | |
| 1514 | // Bottom-right margins. |
| 1515 | br = |
| 1516 | { |
| 1517 | x : thisPos.x + ew + margin( this, 'right' ) - ( ( parentPos.x ) + cw ) || 0, |
| 1518 | y : thisPos.y + eh + margin( this, 'bottom' ) - ( ( parentPos.y ) + ch ) || 0 |
| 1519 | }; |
| 1520 | |
| 1521 | // 1. Do the specified alignment as much as possible; |
| 1522 | // 2. Otherwise be smart to scroll only the minimum amount; |
| 1523 | // 3. Never cut at the top; |
| 1524 | // 4. DO NOT scroll when already visible. |
| 1525 | if ( lt.y < 0 || br.y > 0 ) |
| 1526 | { |
| 1527 | scrollBy( 0, |
| 1528 | alignToTop === true ? lt.y : |
| 1529 | alignToTop === false ? br.y : |
| 1530 | lt.y < 0 ? lt.y : br.y ); |
| 1531 | } |
| 1532 | |
| 1533 | if ( hscroll && ( lt.x < 0 || br.x > 0 ) ) |
| 1534 | scrollBy( lt.x < 0 ? lt.x : br.x, 0 ); |
| 1535 | }, |
| 1536 | |
| 1537 | /** |
| 1538 | * Make any page element visible inside of the browser viewport. |
| 1539 | * @param {Boolean} [alignToTop] |
| 1540 | */ |
| 1541 | scrollIntoView : function( alignToTop ) |
| 1542 | { |
| 1543 | var parent = this.getParent(); |
| 1544 | if ( !parent ) return; |
| 1545 | |
| 1546 | // Scroll the element into parent container from the inner out. |
| 1547 | do |
| 1548 | { |
| 1549 | // Check ancestors that overflows. |
| 1550 | var overflowed = |
| 1551 | parent.$.clientWidth && parent.$.clientWidth < parent.$.scrollWidth |
| 1552 | || parent.$.clientHeight && parent.$.clientHeight < parent.$.scrollHeight; |
| 1553 | |
| 1554 | if ( overflowed ) |
| 1555 | this.scrollIntoParent( parent, alignToTop, 1 ); |
| 1556 | |
| 1557 | // Walk across the frame. |
| 1558 | if ( parent.is( 'html' ) ) |
| 1559 | { |
| 1560 | var win = parent.getWindow(); |
| 1561 | |
| 1562 | // Avoid security error. |
| 1563 | try |
| 1564 | { |
| 1565 | var iframe = win.$.frameElement; |
| 1566 | iframe && ( parent = new CKEDITOR.dom.element( iframe ) ); |
| 1567 | } |
| 1568 | catch(er){} |
| 1569 | } |
| 1570 | } |
| 1571 | while ( parent = parent.getParent() ); |
| 1572 | }, |
| 1573 | |