1 /** 2 * Copyright (C) 2010-2014 KO GmbH <copyright@kogmbh.com> 3 * 4 * @licstart 5 * This file is part of WebODF. 6 * 7 * WebODF is free software: you can redistribute it and/or modify it 8 * under the terms of the GNU Affero General Public License (GNU AGPL) 9 * as published by the Free Software Foundation, either version 3 of 10 * the License, or (at your option) any later version. 11 * 12 * WebODF is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Affero General Public License for more details. 16 * 17 * You should have received a copy of the GNU Affero General Public License 18 * along with WebODF. If not, see <http://www.gnu.org/licenses/>. 19 * @licend 20 * 21 * @source: http://www.webodf.org/ 22 * @source: https://github.com/kogmbh/WebODF/ 23 */ 24 25 /*global gui*/ 26 27 /** 28 * Viewport controller for a single scroll pane capable of scrolling either 29 * horizontally or vertically. 30 * 31 * @constructor 32 * @implements {gui.Viewport} 33 * @param {!HTMLElement} scrollPane 34 */ 35 gui.SingleScrollViewport = function(scrollPane) { 36 "use strict"; 37 var VIEW_PADDING_PX = 5; 38 39 /** 40 * Pad the client rect with the supplied margin 41 * @param {!core.SimpleClientRect} clientRect 42 * @param {!core.SimpleClientRect} margin 43 * @return {!core.SimpleClientRect} 44 */ 45 function shrinkClientRectByMargin(clientRect, margin) { 46 return { 47 left: clientRect.left + margin.left, 48 top: clientRect.top + margin.top, 49 right: clientRect.right - margin.right, 50 bottom: clientRect.bottom - margin.bottom 51 }; 52 } 53 54 /** 55 * @param {!core.SimpleClientRect} clientRect 56 * @return {!number} 57 */ 58 function height(clientRect) { 59 return clientRect.bottom - clientRect.top; 60 } 61 62 /** 63 * @param {!core.SimpleClientRect} clientRect 64 * @return {!number} 65 */ 66 function width(clientRect) { 67 return clientRect.right - clientRect.left; 68 } 69 70 /** 71 * @param {?core.SimpleClientRect} clientRect 72 * @param {!boolean=} alignWithTop 73 * @return {undefined} 74 */ 75 this.scrollIntoView = function(clientRect, alignWithTop) { 76 var verticalScrollbarHeight = scrollPane.offsetHeight - scrollPane.clientHeight, 77 horizontalScrollbarWidth = scrollPane.offsetWidth - scrollPane.clientWidth, 78 nonNullClientRect, 79 scrollPaneRect = scrollPane.getBoundingClientRect(), 80 /**@type{!core.SimpleClientRect}*/ 81 paneRect; 82 83 if (!clientRect || !scrollPaneRect) { 84 return; 85 } 86 87 nonNullClientRect = /**@type{!core.SimpleClientRect}*/(clientRect); 88 89 // Visible area is slightly different from the BCR 90 // See https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements 91 paneRect = shrinkClientRectByMargin(/**@type{!core.SimpleClientRect}*/(scrollPaneRect), { 92 top: VIEW_PADDING_PX, 93 bottom: verticalScrollbarHeight + VIEW_PADDING_PX, 94 left: VIEW_PADDING_PX, 95 right: horizontalScrollbarWidth + VIEW_PADDING_PX 96 }); 97 98 // Vertical adjustment 99 if (alignWithTop || nonNullClientRect.top < paneRect.top) { 100 // Scroll top down into view 101 scrollPane.scrollTop -= paneRect.top - nonNullClientRect.top; 102 } else if (nonNullClientRect.top > paneRect.bottom || nonNullClientRect.bottom > paneRect.bottom) { 103 // Scroll top *up* into view, potentially including bottom if possible 104 if (height(nonNullClientRect) <= height(paneRect)) { 105 // Whole region fits vertically on-screen, so scroll bottom into view 106 scrollPane.scrollTop += nonNullClientRect.bottom - paneRect.bottom; 107 } else { 108 // Only one end will fit on screen, so scroll the top as high as possible 109 scrollPane.scrollTop += nonNullClientRect.top - paneRect.top; 110 } 111 } 112 113 // Horizontal adjustment - Logic mirrors vertical adjustment 114 if (nonNullClientRect.left < paneRect.left) { 115 scrollPane.scrollLeft -= paneRect.left - nonNullClientRect.left; 116 } else if (nonNullClientRect.right > paneRect.right) { 117 if (width(nonNullClientRect) <= width(paneRect)) { 118 scrollPane.scrollLeft += nonNullClientRect.right - paneRect.right; 119 } else { 120 scrollPane.scrollLeft -= paneRect.left - nonNullClientRect.left; 121 } 122 } 123 }; 124 };