mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-15 09:34:13 +00:00
Merge branch '590-the-currently-selected-view-is-not-scrolled-to-automatically-in-the-viewscontext-menu' into 'develop'
Resolve "The currently selected view is not scrolled to automatically in the ViewsContext menu" Closes #591 and #590 See merge request bramw/baserow!390
This commit is contained in:
commit
c684f3f942
4 changed files with 157 additions and 43 deletions
changelog.md
web-frontend/modules
|
@ -24,6 +24,8 @@
|
|||
'before_id' when moving a row by introducing a decorator to validate query parameters.
|
||||
* Fixed bug where copying a cell containing a null value resulted in an error.
|
||||
* Added "Multiple Select" field type.
|
||||
* Fixed a bug where the currently selected view was not in the viewport of the parent.
|
||||
* Fixed a bug where views context would not scroll down after a new view has been added.
|
||||
|
||||
## Released (2021-08-11)
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { isDomElement, isElement } from '@baserow/modules/core/utils/dom'
|
||||
import dropdownHelpers from './dropdownHelpers'
|
||||
|
||||
export default {
|
||||
mixins: [dropdownHelpers],
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Number, Boolean, Object],
|
||||
|
@ -256,44 +258,14 @@ export default {
|
|||
* to is the first viewable item in the dropdown window.
|
||||
*/
|
||||
getScrollTopAmountForNextChild(itemToScrollTo, isArrowUp) {
|
||||
// Styles of the itemToScroll to. Needed in order to get margins and height
|
||||
const itemToScrollToStyles =
|
||||
itemToScrollTo.$el.currentStyle ||
|
||||
window.getComputedStyle(itemToScrollTo.$el)
|
||||
|
||||
// Styles of the ref items (the dropdown window). Needed in order to get
|
||||
// ::before height and ::after height
|
||||
const dropdownWindowBeforeStyles =
|
||||
this.$refs.items.currentStyle ||
|
||||
window.getComputedStyle(this.$refs.items, ':before')
|
||||
|
||||
const dropdownWindowAfterStyles =
|
||||
this.$refs.items.currentStyle ||
|
||||
window.getComputedStyle(this.$refs.items, ':after')
|
||||
|
||||
const dropdownWindowBeforeHeight = parseInt(
|
||||
dropdownWindowBeforeStyles.height
|
||||
)
|
||||
const dropdownWindowAfterHeight = parseInt(
|
||||
dropdownWindowAfterStyles.height
|
||||
)
|
||||
const dropdownWindowHeight = this.$refs.items.clientHeight
|
||||
|
||||
const itemHeight = parseInt(itemToScrollToStyles.height)
|
||||
const itemMarginTop = parseInt(itemToScrollToStyles.marginTop)
|
||||
const itemMarginBottom = parseInt(itemToScrollToStyles.marginBottom)
|
||||
const itemHeightWithMargins =
|
||||
itemHeight + itemMarginTop + itemMarginBottom
|
||||
|
||||
// Based on the values set in the SCSS files. The height of a dropdowns select
|
||||
// item is set to 32px and the height of the select_items window is set to 4 *
|
||||
// 36 (select item height plus margins) plus 20 (heights of before and after
|
||||
// pseudo elements) so that there is room for four elements
|
||||
const itemsInView =
|
||||
(dropdownWindowHeight -
|
||||
dropdownWindowBeforeHeight -
|
||||
dropdownWindowAfterHeight) /
|
||||
itemHeightWithMargins
|
||||
const {
|
||||
parentContainerHeight,
|
||||
parentContainerAfterHeight,
|
||||
parentContainerBeforeHeight,
|
||||
itemHeightWithMargins,
|
||||
itemMarginTop,
|
||||
itemsInView,
|
||||
} = this.getStyleProperties(this.$refs.items, itemToScrollTo.$el)
|
||||
|
||||
// Get the direction of the scrolling.
|
||||
const movingDownwards = !isArrowUp
|
||||
|
@ -306,7 +278,7 @@ export default {
|
|||
// of the dropdown minus the full height of the element
|
||||
const nextItemOutOfView =
|
||||
itemToScrollTo.$el.offsetTop - this.$refs.items.scrollTop >
|
||||
dropdownWindowHeight - itemHeightWithMargins
|
||||
parentContainerHeight - itemHeightWithMargins
|
||||
|
||||
// prevItemOutOfView can be used if one wants to check if the item to scroll
|
||||
// to is out of view of the current dropdowns top scroll position.
|
||||
|
@ -317,7 +289,7 @@ export default {
|
|||
|
||||
// When the user is scrolling downwards (i.e. pressing key down)
|
||||
// and the itemToScrollTo is out of view we want to add the height of the
|
||||
// elements preceding the itemToScrollTo plus the dropdownWindowBeforeHeight.
|
||||
// elements preceding the itemToScrollTo plus the parentContainerBeforeHeight.
|
||||
// This can be achieved by removing said heights from the itemToScrollTo's
|
||||
// offsetTop
|
||||
if (nextItemOutOfView && movingDownwards) {
|
||||
|
@ -327,7 +299,7 @@ export default {
|
|||
return (
|
||||
itemToScrollTo.$el.offsetTop -
|
||||
elementsHeightBeforeItemToScrollTo -
|
||||
dropdownWindowBeforeHeight
|
||||
parentContainerBeforeHeight
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -339,7 +311,7 @@ export default {
|
|||
return (
|
||||
itemToScrollTo.$el.offsetTop -
|
||||
itemMarginTop -
|
||||
dropdownWindowAfterHeight
|
||||
parentContainerAfterHeight
|
||||
)
|
||||
}
|
||||
|
||||
|
|
71
web-frontend/modules/core/mixins/dropdownHelpers.js
Normal file
71
web-frontend/modules/core/mixins/dropdownHelpers.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
export default {
|
||||
methods: {
|
||||
/**
|
||||
* This method is a helper for extracting certain style properties of a parent container
|
||||
* and one of it's child items. This is helpful for determining the amount of pixels
|
||||
* to scroll in order to get a child element aligned at the bottom of the parent container,
|
||||
* either when scrolling by keydown/keyup or manually setting a scroll position.
|
||||
*
|
||||
* It expects the parent container to have :before and :after pseudo elements.
|
||||
*
|
||||
* Returns an object containing the following:
|
||||
*
|
||||
* parentContainerHeight: The height of the parent container.
|
||||
* parentContainerAfterHeight: The height of the parents 'after' pseudo element.
|
||||
* parentContainerBeforeHeight: The height of the parents 'before' pseudo element.
|
||||
* itemHeightWithMargins: The height of the child item including its margins.
|
||||
* itemMarginTop: The top margin of the child item.
|
||||
* itemMarginBottom: The bottom margin of the child item.
|
||||
* itemsInView: The amount of times the child item fits into the parent viewport.
|
||||
*/
|
||||
getStyleProperties(parentContainer, childItem) {
|
||||
// Styles of the childItem. Needed in order to get margins and height
|
||||
const childItemStyles =
|
||||
childItem.currentStyle || window.getComputedStyle(childItem)
|
||||
|
||||
// Styles of the parent container. Needed in order to get
|
||||
// ::before height and ::after height
|
||||
const parentContainerBeforeStyles =
|
||||
parentContainer.currentStyle ||
|
||||
window.getComputedStyle(parentContainer, ':before')
|
||||
|
||||
const parentContainerAfterStyles =
|
||||
parentContainer.currentStyle ||
|
||||
window.getComputedStyle(parentContainer, ':after')
|
||||
|
||||
const parentContainerBeforeHeight = parseInt(
|
||||
parentContainerBeforeStyles.height
|
||||
)
|
||||
const parentContainerAfterHeight = parseInt(
|
||||
parentContainerAfterStyles.height
|
||||
)
|
||||
const parentContainerHeight = parentContainer.clientHeight
|
||||
|
||||
const itemHeight = parseInt(childItemStyles.height)
|
||||
const itemMarginTop = parseInt(childItemStyles.marginTop)
|
||||
const itemMarginBottom = parseInt(childItemStyles.marginBottom)
|
||||
const itemHeightWithMargins =
|
||||
itemHeight + itemMarginTop + itemMarginBottom
|
||||
|
||||
// Based on the values set in the SCSS files. The height of a dropdowns select
|
||||
// item is set to 32px and the height of the select_items window is set to 4 *
|
||||
// 36 (select item height plus margins) plus 20 (heights of before and after
|
||||
// pseudo elements) so that there is room for four elements
|
||||
const itemsInView =
|
||||
(parentContainerHeight -
|
||||
parentContainerBeforeHeight -
|
||||
parentContainerAfterHeight) /
|
||||
itemHeightWithMargins
|
||||
|
||||
return {
|
||||
parentContainerHeight,
|
||||
parentContainerAfterHeight,
|
||||
parentContainerBeforeHeight,
|
||||
itemHeightWithMargins,
|
||||
itemMarginTop,
|
||||
itemMarginBottom,
|
||||
itemsInView,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
|
@ -14,11 +14,13 @@
|
|||
</div>
|
||||
<ul
|
||||
v-if="!isLoading && views.length > 0"
|
||||
ref="dropdown"
|
||||
v-auto-overflow-scroll
|
||||
class="select__items"
|
||||
>
|
||||
<ViewsContextItem
|
||||
v-for="view in searchAndOrder(views)"
|
||||
:ref="'view-' + view.id"
|
||||
:key="view.id"
|
||||
v-sortable="{ id: view.id, update: order, marginTop: -1.5 }"
|
||||
:view="view"
|
||||
|
@ -51,6 +53,7 @@
|
|||
:ref="'createViewModal' + type"
|
||||
:table="table"
|
||||
:view-type="viewType"
|
||||
@created="scrollViewDropdownToBottom()"
|
||||
></CreateViewModal>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -62,6 +65,7 @@
|
|||
import { mapState } from 'vuex'
|
||||
|
||||
import context from '@baserow/modules/core/mixins/context'
|
||||
import dropdownHelpers from '@baserow/modules/core/mixins/dropdownHelpers'
|
||||
import { notifyIf } from '@baserow/modules/core/utils/error'
|
||||
import ViewsContextItem from '@baserow/modules/database/components/view/ViewsContextItem'
|
||||
import CreateViewModal from '@baserow/modules/database/components/view/CreateViewModal'
|
||||
|
@ -72,7 +76,7 @@ export default {
|
|||
ViewsContextItem,
|
||||
CreateViewModal,
|
||||
},
|
||||
mixins: [context],
|
||||
mixins: [context, dropdownHelpers],
|
||||
props: {
|
||||
table: {
|
||||
type: Object,
|
||||
|
@ -102,11 +106,76 @@ export default {
|
|||
isLoaded: (state) => state.view.loaded,
|
||||
}),
|
||||
},
|
||||
mounted() {
|
||||
this.scrollViewDropdownIfNeeded()
|
||||
},
|
||||
methods: {
|
||||
selectedView(view) {
|
||||
this.hide()
|
||||
this.$emit('selected-view', view)
|
||||
},
|
||||
/*
|
||||
If the currently selected view is not visible inside the dropdown we need to
|
||||
scroll just enough so that the selected view is visible as the last element
|
||||
in the dropdown.
|
||||
*/
|
||||
scrollViewDropdownIfNeeded() {
|
||||
const dropdownElement = this.$refs.dropdown
|
||||
const selectedViewItem = this.getSelectedViewItem()
|
||||
const dropdownHeight = dropdownElement.clientHeight
|
||||
if (
|
||||
this.isSelectedViewOutOfDropdownView(selectedViewItem, dropdownHeight)
|
||||
) {
|
||||
dropdownElement.scrollTop = this.calculateOffsetToSelectedViewItem(
|
||||
dropdownElement,
|
||||
selectedViewItem
|
||||
)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* This method scrolls the ViewDropdown to the bottom
|
||||
*/
|
||||
scrollViewDropdownToBottom() {
|
||||
this.$refs.dropdown.scrollTop = this.$refs.dropdown.scrollHeight
|
||||
},
|
||||
/**
|
||||
* This method filters the view elements and returns the currently selected
|
||||
* view dom item based on whether or not it is selected.
|
||||
*/
|
||||
getSelectedViewItem() {
|
||||
const selectedViewArray = this.views.filter((item) => item._.selected)
|
||||
const selectedViewItemID = selectedViewArray[0].id
|
||||
return this.$refs[`view-${selectedViewItemID}`][0].$el
|
||||
},
|
||||
/**
|
||||
* This method calculates whether or not the selectedViewItem is fully visible
|
||||
* inside the ViewContext dropdown or not
|
||||
*/
|
||||
isSelectedViewOutOfDropdownView(selectedViewItem, dropdownHeight) {
|
||||
const selectedOffsetPlusHeight =
|
||||
selectedViewItem.offsetTop + selectedViewItem.clientHeight
|
||||
return selectedOffsetPlusHeight > dropdownHeight
|
||||
},
|
||||
/**
|
||||
* This method calculates the necessary offsetTop of the dropdown element so that
|
||||
* the selected view item is the bottom element.
|
||||
*/
|
||||
calculateOffsetToSelectedViewItem(dropdownElement, selectedViewItem) {
|
||||
const {
|
||||
parentContainerBeforeHeight,
|
||||
itemHeightWithMargins,
|
||||
itemsInView,
|
||||
} = this.getStyleProperties(dropdownElement, selectedViewItem)
|
||||
|
||||
const viewItemsBeforeSelectedViewItemHeight =
|
||||
(itemsInView - 1) * itemHeightWithMargins
|
||||
|
||||
return (
|
||||
selectedViewItem.offsetTop -
|
||||
viewItemsBeforeSelectedViewItemHeight -
|
||||
parentContainerBeforeHeight
|
||||
)
|
||||
},
|
||||
toggleCreateViewModal(type) {
|
||||
const target = this.$refs['createViewModalToggle' + type][0]
|
||||
this.$refs['createViewModal' + type][0].toggle(target)
|
||||
|
|
Loading…
Add table
Reference in a new issue