Removing last item padding; Improving scroll restoration, fixing #618
This commit is contained in:
@ -134289,30 +134289,32 @@ var App = /*#__PURE__*/function (_React$Component) {
|
||||
}, {
|
||||
key: "componentDidUpdate",
|
||||
value: function componentDidUpdate(_ref) {
|
||||
var prevLocation = _ref.location;
|
||||
var prevPathname = _ref.location.pathname;
|
||||
var _this$props3 = this.props,
|
||||
_this$props3$location = _this$props3.location,
|
||||
location = _this$props3$location === void 0 ? {} : _this$props3$location,
|
||||
_this$props3$location = _this$props3.location;
|
||||
_this$props3$location = _this$props3$location === void 0 ? {} : _this$props3$location;
|
||||
var pathname = _this$props3$location.pathname,
|
||||
_this$props3$location2 = _this$props3$location.state;
|
||||
_this$props3$location2 = _this$props3$location2 === void 0 ? {} : _this$props3$location2;
|
||||
var scroll_position = _this$props3$location2.scroll_position,
|
||||
allow_reporting = _this$props3.allow_reporting,
|
||||
uiActions = _this$props3.uiActions,
|
||||
context_menu = _this$props3.context_menu; // When we have navigated to a new route
|
||||
|
||||
if (location !== prevLocation) {
|
||||
if (pathname !== prevPathname) {
|
||||
// Log our pageview
|
||||
if (allow_reporting) {
|
||||
react_ga__WEBPACK_IMPORTED_MODULE_4__["default"].set({
|
||||
page: location.pathname
|
||||
page: pathname
|
||||
});
|
||||
react_ga__WEBPACK_IMPORTED_MODULE_4__["default"].pageview(location.pathname);
|
||||
react_ga__WEBPACK_IMPORTED_MODULE_4__["default"].pageview(pathname);
|
||||
} // If the location has a "scroll_position" state variable, scroll to it.
|
||||
// This is invisibly injected to the history by the Link component when navigating, so
|
||||
// hitting back in the browser allows us to restore the position
|
||||
|
||||
|
||||
var location_state = location.state || {};
|
||||
|
||||
if (location_state.scroll_position) {
|
||||
Object(_util_helpers__WEBPACK_IMPORTED_MODULE_50__["scrollTo"])(parseInt(location_state.scroll_position), false);
|
||||
if (scroll_position) {
|
||||
Object(_util_helpers__WEBPACK_IMPORTED_MODULE_50__["scrollTo"])(parseInt(scroll_position, 10), false);
|
||||
}
|
||||
|
||||
uiActions.toggleSidebar(false);
|
||||
@ -141780,11 +141782,13 @@ var LazyLoadListener = /*#__PURE__*/function (_React$Component) {
|
||||
/*!***********************************!*\
|
||||
!*** ./src/js/components/Link.js ***!
|
||||
\***********************************/
|
||||
/*! exports provided: default */
|
||||
/*! exports provided: default, Link, updateScrollPosition */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Link", function() { return Link; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "updateScrollPosition", function() { return updateScrollPosition; });
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
||||
/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router-dom/esm/react-router-dom.js");
|
||||
@ -141800,21 +141804,46 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
|
||||
|
||||
|
||||
|
||||
var updateScrollPosition = function updateScrollPosition(_ref) {
|
||||
var _ref$retainScroll = _ref.retainScroll,
|
||||
retainScroll = _ref$retainScroll === void 0 ? false : _ref$retainScroll,
|
||||
_ref$scrollTarget = _ref.scrollTarget,
|
||||
scrollTarget = _ref$scrollTarget === void 0 ? 0 : _ref$scrollTarget,
|
||||
history = _ref.history,
|
||||
_ref$location = _ref.location,
|
||||
state = _ref$location.state,
|
||||
pathname = _ref$location.pathname;
|
||||
// Fetch the current scroll position of our #main element and save to our history's state, so
|
||||
// clicking 'back' etc will restore the previous scroll position.
|
||||
// This doesn't trigger lazy-load elements (unless scrolling exposes the LazyLoader component).
|
||||
var main = document.getElementById('main');
|
||||
history.replace(pathname, _objectSpread(_objectSpread({}, state), {}, {
|
||||
scroll_position: main.scrollTop,
|
||||
previous: {
|
||||
pathname: pathname
|
||||
}
|
||||
})); // And now scroll to the top of the page. This can be disabled to allow in-page navigation of
|
||||
// tabs, etc
|
||||
|
||||
if (!retainScroll) Object(_util_helpers__WEBPACK_IMPORTED_MODULE_2__["scrollTo"])(scrollTarget, scrollTarget);
|
||||
};
|
||||
/**
|
||||
* Extends react-router's Link but provides the ability to hook in to the navigation event
|
||||
* which lets us scroll to the top of our <main> for a more traditional navigation experience
|
||||
* */
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (function (_ref) {
|
||||
var retainScroll = _ref.retainScroll,
|
||||
scrollToProp = _ref.scrollTo,
|
||||
onContextMenu = _ref.onContextMenu,
|
||||
_ref$className = _ref.className,
|
||||
className = _ref$className === void 0 ? '' : _ref$className,
|
||||
activeClassName = _ref.activeClassName,
|
||||
to = _ref.to,
|
||||
exact = _ref.exact,
|
||||
children = _ref.children;
|
||||
|
||||
var Link = function Link(_ref2) {
|
||||
var retainScroll = _ref2.retainScroll,
|
||||
scrollTarget = _ref2.scrollTo,
|
||||
onContextMenu = _ref2.onContextMenu,
|
||||
_ref2$className = _ref2.className,
|
||||
className = _ref2$className === void 0 ? '' : _ref2$className,
|
||||
activeClassName = _ref2.activeClassName,
|
||||
to = _ref2.to,
|
||||
exact = _ref2.exact,
|
||||
children = _ref2.children;
|
||||
if (!to) return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
|
||||
className: className,
|
||||
"data-qa-node": "span",
|
||||
@ -141824,19 +141853,12 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
var location = Object(react_router_dom__WEBPACK_IMPORTED_MODULE_1__["useLocation"])();
|
||||
|
||||
var onClick = function onClick() {
|
||||
// Fetch the current scroll position of our #main element and save to our history's state, so
|
||||
// clicking 'back' etc will restore the previous scroll position.
|
||||
// This doesn't trigger lazy-load elements (unless scrolling exposes the LazyLoader component).
|
||||
var main = document.getElementById('main');
|
||||
history.replace(location.pathname, _objectSpread(_objectSpread({}, location.state), {}, {
|
||||
scroll_position: main.scrollTop,
|
||||
previous: {
|
||||
pathname: location.pathname
|
||||
}
|
||||
})); // Allow a link to disable auto-scrolling to the top of the page
|
||||
// on navigation. Useful for tabs, etc.
|
||||
|
||||
if (!retainScroll) Object(_util_helpers__WEBPACK_IMPORTED_MODULE_2__["scrollTo"])(scrollToProp, scrollToProp);
|
||||
return updateScrollPosition({
|
||||
history: history,
|
||||
location: location,
|
||||
retainScroll: retainScroll,
|
||||
scrollTarget: scrollTarget
|
||||
});
|
||||
}; // Decode both links. This handles issues where one link is encoded and the other isn't, but
|
||||
// they're otherwise identical
|
||||
|
||||
@ -141852,10 +141874,13 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
onContextMenu: onContextMenu,
|
||||
className: "".concat(className, " ").concat(active),
|
||||
to: to,
|
||||
"data-qa-node": "Link",
|
||||
"data-qa-node": "RouterLink",
|
||||
"data-qa-file": "Link"
|
||||
}, children);
|
||||
});
|
||||
};
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (Link);
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
@ -142002,15 +142027,13 @@ __webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _Icon__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./Icon */ "./src/js/components/Icon.js");
|
||||
/* harmony import */ var _Thumbnail__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./Thumbnail */ "./src/js/components/Thumbnail.js");
|
||||
/* harmony import */ var _Popularity__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./Popularity */ "./src/js/components/Popularity.js");
|
||||
/* harmony import */ var _Link__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./Link */ "./src/js/components/Link.js");
|
||||
/* harmony import */ var _locale__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../locale */ "./src/js/locale/index.js");
|
||||
/* harmony import */ var _util_format__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../util/format */ "./src/js/util/format.js");
|
||||
/* harmony import */ var _util_helpers__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../util/helpers */ "./src/js/util/helpers.js");
|
||||
/* harmony import */ var _locale__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../locale */ "./src/js/locale/index.js");
|
||||
/* harmony import */ var _util_format__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../util/format */ "./src/js/util/format.js");
|
||||
/* harmony import */ var _util_helpers__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../util/helpers */ "./src/js/util/helpers.js");
|
||||
/* harmony import */ var _Link__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./Link */ "./src/js/components/Link.js");
|
||||
/* harmony import */ var _services_ui_actions__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../services/ui/actions */ "./src/js/services/ui/actions.js");
|
||||
/* harmony import */ var _services_lastfm_actions__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../services/lastfm/actions */ "./src/js/services/lastfm/actions.js");
|
||||
/* harmony import */ var _services_mopidy_actions__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../services/mopidy/actions */ "./src/js/services/mopidy/actions.js");
|
||||
/* harmony import */ var _services_spotify_actions__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../services/spotify/actions */ "./src/js/services/spotify/actions.js");
|
||||
|
||||
/* harmony import */ var _services_mopidy_actions__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../services/mopidy/actions */ "./src/js/services/mopidy/actions.js");
|
||||
/* harmony import */ var _services_spotify_actions__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../services/spotify/actions */ "./src/js/services/spotify/actions.js");
|
||||
|
||||
|
||||
|
||||
@ -142040,7 +142063,7 @@ var getValue = function getValue() {
|
||||
{
|
||||
var total = item.tracks_total;
|
||||
if (!total && !value) return null;
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_12__["I18n"], {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_11__["I18n"], {
|
||||
path: "specs.tracks",
|
||||
count: Object(_NiceNumber__WEBPACK_IMPORTED_MODULE_5__["nice_number"])(total || value.length),
|
||||
"data-qa-node": "I18n",
|
||||
@ -142059,7 +142082,7 @@ var getValue = function getValue() {
|
||||
"data-qa-file": "ListItem"
|
||||
});
|
||||
if (!_total && !array) return null;
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_12__["I18n"], {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_11__["I18n"], {
|
||||
path: "specs.artists",
|
||||
count: Object(_NiceNumber__WEBPACK_IMPORTED_MODULE_5__["nice_number"])(_total || array.length),
|
||||
"data-qa-node": "I18n",
|
||||
@ -142072,7 +142095,7 @@ var getValue = function getValue() {
|
||||
var _total2 = item.albums_total,
|
||||
_array = item.albums_uris;
|
||||
if (!_total2 && !_array) return null;
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_12__["I18n"], {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_11__["I18n"], {
|
||||
path: "specs.albums",
|
||||
count: _total2 || _array.length,
|
||||
"data-qa-node": "I18n",
|
||||
@ -142083,7 +142106,7 @@ var getValue = function getValue() {
|
||||
case 'source':
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Icon__WEBPACK_IMPORTED_MODULE_8__["default"], {
|
||||
type: "fontawesome",
|
||||
name: Object(_util_helpers__WEBPACK_IMPORTED_MODULE_14__["sourceIcon"])(item.uri),
|
||||
name: Object(_util_helpers__WEBPACK_IMPORTED_MODULE_13__["sourceIcon"])(item.uri),
|
||||
fixedWidth: true,
|
||||
"data-qa-node": "Icon",
|
||||
"data-qa-file": "ListItem"
|
||||
@ -142098,7 +142121,7 @@ var getValue = function getValue() {
|
||||
|
||||
switch (name) {
|
||||
case 'followers':
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_12__["I18n"], {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_11__["I18n"], {
|
||||
path: "specs.followers",
|
||||
count: Object(_NiceNumber__WEBPACK_IMPORTED_MODULE_5__["nice_number"])(value),
|
||||
"data-qa-node": "I18n",
|
||||
@ -142106,7 +142129,7 @@ var getValue = function getValue() {
|
||||
});
|
||||
|
||||
case 'listeners':
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_12__["I18n"], {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_11__["I18n"], {
|
||||
path: "specs.listeners",
|
||||
count: Object(_NiceNumber__WEBPACK_IMPORTED_MODULE_5__["nice_number"])(value),
|
||||
"data-qa-node": "I18n",
|
||||
@ -142114,7 +142137,7 @@ var getValue = function getValue() {
|
||||
});
|
||||
|
||||
case 'added_at':
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_12__["I18n"], {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_11__["I18n"], {
|
||||
path: "specs.added_ago",
|
||||
time: Object(_Dater__WEBPACK_IMPORTED_MODULE_4__["dater"])('ago', value),
|
||||
"data-qa-node": "I18n",
|
||||
@ -142122,7 +142145,7 @@ var getValue = function getValue() {
|
||||
});
|
||||
|
||||
case 'last_modified':
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_12__["I18n"], {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_11__["I18n"], {
|
||||
path: "specs.updated_ago",
|
||||
time: Object(_Dater__WEBPACK_IMPORTED_MODULE_4__["dater"])('ago', value),
|
||||
"data-qa-node": "I18n",
|
||||
@ -142174,20 +142197,21 @@ var ListItem = function ListItem(_ref) {
|
||||
var spotify_available = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["useSelector"])(function (state) {
|
||||
return state.spotify.access_token;
|
||||
});
|
||||
var history = Object(react_router_dom__WEBPACK_IMPORTED_MODULE_2__["useHistory"])(); // Load images
|
||||
var history = Object(react_router_dom__WEBPACK_IMPORTED_MODULE_2__["useHistory"])();
|
||||
var location = Object(react_router_dom__WEBPACK_IMPORTED_MODULE_2__["useLocation"])(); // Load images
|
||||
|
||||
Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(function () {
|
||||
if (!item.images) {
|
||||
switch (item.type) {
|
||||
case 'artist':
|
||||
if (spotify_available) {
|
||||
dispatch(_services_spotify_actions__WEBPACK_IMPORTED_MODULE_18__["getArtistImages"](item));
|
||||
dispatch(_services_spotify_actions__WEBPACK_IMPORTED_MODULE_17__["getArtistImages"](item));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'album':
|
||||
dispatch(_services_mopidy_actions__WEBPACK_IMPORTED_MODULE_17__["getImages"]([item.uri]));
|
||||
dispatch(_services_mopidy_actions__WEBPACK_IMPORTED_MODULE_16__["getImages"]([item.uri]));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -142224,13 +142248,16 @@ var ListItem = function ListItem(_ref) {
|
||||
} else if (item.link) {
|
||||
to = item.link;
|
||||
} else {
|
||||
to = "/".concat(item.type, "/").concat(Object(_util_format__WEBPACK_IMPORTED_MODULE_13__["encodeUri"])(item.uri));
|
||||
to = "/".concat(item.type, "/").concat(Object(_util_format__WEBPACK_IMPORTED_MODULE_12__["encodeUri"])(item.uri));
|
||||
}
|
||||
|
||||
if (e.target.tagName.toLowerCase() !== 'a') {
|
||||
Object(_Link__WEBPACK_IMPORTED_MODULE_14__["updateScrollPosition"])({
|
||||
location: location,
|
||||
history: history
|
||||
});
|
||||
e.preventDefault();
|
||||
history.push(to);
|
||||
Object(_util_helpers__WEBPACK_IMPORTED_MODULE_14__["scrollTo"])();
|
||||
}
|
||||
};
|
||||
|
||||
@ -146284,7 +146311,6 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
|
||||
|
||||
var SmartListBatch = react_in_viewport__WEBPACK_IMPORTED_MODULE_1___default()(function (_ref) {
|
||||
var items = _ref.items,
|
||||
isFirst = _ref.isFirst,
|
||||
inViewport = _ref.inViewport,
|
||||
forwardedRef = _ref.forwardedRef,
|
||||
setItemHeight = _ref.setItemHeight,
|
||||
@ -146294,7 +146320,9 @@ var SmartListBatch = react_in_viewport__WEBPACK_IMPORTED_MODULE_1___default()(fu
|
||||
batchIndex = _ref.batchIndex,
|
||||
chunkSize = _ref.chunkSize,
|
||||
_ref$className = _ref.className,
|
||||
className = _ref$className === void 0 ? '' : _ref$className;
|
||||
className = _ref$className === void 0 ? '' : _ref$className,
|
||||
isFirst = _ref.isFirst,
|
||||
isLast = _ref.isLast;
|
||||
// Listen for changes to our height, and pass it up to our Grid. This is then used to build the
|
||||
// placeholder elements when out of viewport. We only care about the first item because this
|
||||
// represents the same heights for everything else (in almost all circumstances).
|
||||
@ -146319,9 +146347,9 @@ var SmartListBatch = react_in_viewport__WEBPACK_IMPORTED_MODULE_1___default()(fu
|
||||
ref: forwardedRef,
|
||||
"data-qa-node": "div",
|
||||
"data-qa-file": "SmartList"
|
||||
}, inViewport || isFirst ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
}, inViewport || isFirst || isLast ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "smart-list__batch__inner",
|
||||
style: isFirst ? {} : {
|
||||
style: isFirst || isLast ? {} : {
|
||||
minHeight: itemHeight
|
||||
},
|
||||
"data-qa-node": "div",
|
||||
@ -146362,10 +146390,11 @@ var SmartList = /*#__PURE__*/Object(react__WEBPACK_IMPORTED_MODULE_0__["memo"])(
|
||||
itemHeight = _useState2[0],
|
||||
setItemHeight = _useState2[1];
|
||||
|
||||
var chunks = Object(lodash__WEBPACK_IMPORTED_MODULE_2__["chunk"])(items, chunkSize);
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_ErrorBoundary__WEBPACK_IMPORTED_MODULE_3__["default"], {
|
||||
"data-qa-node": "ErrorBoundary",
|
||||
"data-qa-file": "SmartList"
|
||||
}, Object(lodash__WEBPACK_IMPORTED_MODULE_2__["chunk"])(items, chunkSize).map(function (chunked, index) {
|
||||
}, chunks.map(function (chunked, index) {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(SmartListBatch, {
|
||||
key: "smart-list__batch-".concat(index) // Yeah yeah, I know; TODO
|
||||
,
|
||||
@ -146376,8 +146405,9 @@ var SmartList = /*#__PURE__*/Object(react__WEBPACK_IMPORTED_MODULE_0__["memo"])(
|
||||
itemProps: itemProps,
|
||||
batchIndex: index,
|
||||
chunkSize: chunkSize,
|
||||
isFirst: index === 0,
|
||||
setItemHeight: setItemHeight,
|
||||
isFirst: index === 0,
|
||||
isLast: index === chunks.length - 1,
|
||||
"data-qa-node": "SmartListBatch",
|
||||
"data-qa-file": "SmartList"
|
||||
});
|
||||
@ -163636,48 +163666,47 @@ var iconFromKeyword = function iconFromKeyword(name) {
|
||||
var scrollTo = function scrollTo() {
|
||||
var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
||||
var smooth_scroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
console.debug('scrollTo', {
|
||||
target: target,
|
||||
smooth_scroll: smooth_scroll
|
||||
});
|
||||
var main = document.getElementById('main'); // Remove our smooth-scroll class
|
||||
var main = document.getElementById('main');
|
||||
|
||||
if (!smooth_scroll) {
|
||||
main.classList.remove('smooth-scroll');
|
||||
} // Target is a number, so treat as pixel position
|
||||
var performScroll = function performScroll() {
|
||||
if (!smooth_scroll) main.classList.remove('smooth-scroll'); // Target is a number, so treat as pixel position
|
||||
|
||||
if (target && Number.isInteger(target)) {
|
||||
if (typeof main.scrollTo === 'function') {
|
||||
console.debug('Scrolling to', {
|
||||
main: main,
|
||||
target: target
|
||||
});
|
||||
main.scrollTo(0, target);
|
||||
} // Target is a string representing a DOM element by class/id
|
||||
|
||||
if (target && Number.isInteger(target)) {
|
||||
if (typeof main.scrollTo === 'function') {
|
||||
main.scrollTop = target;
|
||||
} // Target is a string representing a DOM element by class/id
|
||||
} else if (target) {
|
||||
var element = null;
|
||||
|
||||
} else if (target) {
|
||||
var element = null;
|
||||
if (target.charAt(0) === '#') {
|
||||
element = document.getElementById(target.substring(1));
|
||||
} else if (target.charAt(0) === '.') {
|
||||
element = document.getElementsByClassName(target.substring(1));
|
||||
|
||||
if (target.charAt(0) == '#') {
|
||||
element = document.getElementById(target.substring(1));
|
||||
} else if (target.charAt(0) == '.') {
|
||||
element = document.getElementsByClassName(target.substring(1));
|
||||
if (element.length > 0) {
|
||||
element = element[0];
|
||||
}
|
||||
} else {
|
||||
console.error("Invalid target type '".concat(target, "'. Must start with '#' or '.'."));
|
||||
}
|
||||
|
||||
if (element.length > 0) {
|
||||
element = element[0];
|
||||
if (element && typeof element.scrollIntoView === 'function') {
|
||||
element.scrollIntoView();
|
||||
}
|
||||
} else {
|
||||
console.error("Invalid target type '".concat(target, "'. Must start with '#' or '.'."));
|
||||
main.scrollTop = 0;
|
||||
}
|
||||
|
||||
if (element && typeof element.scrollIntoView === 'function') {
|
||||
element.scrollIntoView();
|
||||
}
|
||||
} else {
|
||||
main.scrollTop = 0;
|
||||
} // Now reinstate smooth scroll
|
||||
if (!smooth_scroll) main.classList.add('smooth-scroll');
|
||||
}; // Give .main a moment to render it's contents
|
||||
|
||||
|
||||
if (!smooth_scroll) {
|
||||
main.classList.add('smooth-scroll');
|
||||
}
|
||||
setTimeout(performScroll, 1);
|
||||
};
|
||||
/**
|
||||
* Upgrade one or many Spotify Playlist URIs
|
||||
|
||||
File diff suppressed because one or more lines are too long
16
mopidy_iris/static/app.min.js
vendored
16
mopidy_iris/static/app.min.js
vendored
File diff suppressed because one or more lines are too long
@ -106,7 +106,7 @@
|
||||
|
||||
// Release details
|
||||
// These are automatically injected to built HTML
|
||||
var build = "1615274990";
|
||||
var build = "1615540275";
|
||||
var version = "3.57.0";
|
||||
|
||||
// Construct the script tag
|
||||
|
||||
@ -161,29 +161,35 @@ export class App extends React.Component {
|
||||
}
|
||||
|
||||
componentDidUpdate({
|
||||
location: prevLocation,
|
||||
location: {
|
||||
pathname: prevPathname,
|
||||
},
|
||||
}) {
|
||||
const {
|
||||
location = {},
|
||||
location: {
|
||||
pathname,
|
||||
state: {
|
||||
scroll_position,
|
||||
} = {},
|
||||
} = {},
|
||||
allow_reporting,
|
||||
uiActions,
|
||||
context_menu,
|
||||
} = this.props;
|
||||
|
||||
// When we have navigated to a new route
|
||||
if (location !== prevLocation) {
|
||||
if (pathname !== prevPathname) {
|
||||
// Log our pageview
|
||||
if (allow_reporting) {
|
||||
ReactGA.set({ page: location.pathname });
|
||||
ReactGA.pageview(location.pathname);
|
||||
ReactGA.set({ page: pathname });
|
||||
ReactGA.pageview(pathname);
|
||||
}
|
||||
|
||||
// If the location has a "scroll_position" state variable, scroll to it.
|
||||
// This is invisibly injected to the history by the Link component when navigating, so
|
||||
// hitting back in the browser allows us to restore the position
|
||||
const location_state = location.state || {};
|
||||
if (location_state.scroll_position) {
|
||||
scrollTo(parseInt(location_state.scroll_position), false);
|
||||
if (scroll_position) {
|
||||
scrollTo(parseInt(scroll_position, 10), false);
|
||||
}
|
||||
|
||||
uiActions.toggleSidebar(false);
|
||||
|
||||
@ -1,15 +1,46 @@
|
||||
import React from 'react';
|
||||
import { Link, useHistory, useLocation } from 'react-router-dom';
|
||||
import { Link as RouterLink, useHistory, useLocation } from 'react-router-dom';
|
||||
import { scrollTo } from '../util/helpers';
|
||||
import { decodeUri } from '../util/format';
|
||||
|
||||
const updateScrollPosition = ({
|
||||
retainScroll = false,
|
||||
scrollTarget = 0,
|
||||
history,
|
||||
location: {
|
||||
state,
|
||||
pathname,
|
||||
},
|
||||
}) => {
|
||||
|
||||
// Fetch the current scroll position of our #main element and save to our history's state, so
|
||||
// clicking 'back' etc will restore the previous scroll position.
|
||||
// This doesn't trigger lazy-load elements (unless scrolling exposes the LazyLoader component).
|
||||
const main = document.getElementById('main');
|
||||
|
||||
history.replace(
|
||||
pathname,
|
||||
{
|
||||
...state,
|
||||
scroll_position: main.scrollTop,
|
||||
previous: {
|
||||
pathname,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// And now scroll to the top of the page. This can be disabled to allow in-page navigation of
|
||||
// tabs, etc
|
||||
if (!retainScroll) scrollTo(scrollTarget, (scrollTarget));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends react-router's Link but provides the ability to hook in to the navigation event
|
||||
* which lets us scroll to the top of our <main> for a more traditional navigation experience
|
||||
* */
|
||||
export default ({
|
||||
const Link = ({
|
||||
retainScroll,
|
||||
scrollTo: scrollToProp,
|
||||
scrollTo: scrollTarget,
|
||||
onContextMenu,
|
||||
className = '',
|
||||
activeClassName,
|
||||
@ -20,28 +51,7 @@ export default ({
|
||||
if (!to) return <span className={className}>{children}</span>;
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
|
||||
const onClick = () => {
|
||||
// Fetch the current scroll position of our #main element and save to our history's state, so
|
||||
// clicking 'back' etc will restore the previous scroll position.
|
||||
// This doesn't trigger lazy-load elements (unless scrolling exposes the LazyLoader component).
|
||||
const main = document.getElementById('main');
|
||||
|
||||
history.replace(
|
||||
location.pathname,
|
||||
{
|
||||
...location.state,
|
||||
scroll_position: main.scrollTop,
|
||||
previous: {
|
||||
pathname: location.pathname,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Allow a link to disable auto-scrolling to the top of the page
|
||||
// on navigation. Useful for tabs, etc.
|
||||
if (!retainScroll) scrollTo(scrollToProp, (scrollToProp));
|
||||
};
|
||||
const onClick = () => updateScrollPosition({ history, location, retainScroll, scrollTarget });
|
||||
|
||||
// Decode both links. This handles issues where one link is encoded and the other isn't, but
|
||||
// they're otherwise identical
|
||||
@ -53,13 +63,20 @@ export default ({
|
||||
// This is used almost solely by the Sidebar navigation
|
||||
const active = history && isLinkActive ? (activeClassName || 'active') : '';
|
||||
return (
|
||||
<Link
|
||||
<RouterLink
|
||||
onClick={onClick}
|
||||
onContextMenu={onContextMenu}
|
||||
className={`${className} ${active}`}
|
||||
to={to}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
</RouterLink>
|
||||
);
|
||||
};
|
||||
|
||||
export default Link;
|
||||
|
||||
export {
|
||||
Link,
|
||||
updateScrollPosition,
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import LinksSentence from './LinksSentence';
|
||||
import { dater } from './Dater';
|
||||
import { nice_number } from './NiceNumber';
|
||||
@ -9,13 +9,12 @@ import ContextMenuTrigger from './ContextMenuTrigger';
|
||||
import Icon from './Icon';
|
||||
import Thumbnail from './Thumbnail';
|
||||
import Popularity from './Popularity';
|
||||
import Link from './Link';
|
||||
import { I18n } from '../locale';
|
||||
import { encodeUri } from '../util/format';
|
||||
import { scrollTo, sourceIcon } from '../util/helpers';
|
||||
import { sourceIcon } from '../util/helpers';
|
||||
import { updateScrollPosition } from './Link';
|
||||
|
||||
import * as uiActions from '../services/ui/actions';
|
||||
import * as lastfmActions from '../services/lastfm/actions';
|
||||
import * as mopidyActions from '../services/mopidy/actions';
|
||||
import * as spotifyActions from '../services/spotify/actions';
|
||||
|
||||
@ -92,6 +91,7 @@ const ListItem = ({
|
||||
const dispatch = useDispatch();
|
||||
const spotify_available = useSelector((state) => state.spotify.access_token);
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
|
||||
// Load images
|
||||
useEffect(() => {
|
||||
@ -142,11 +142,11 @@ const ListItem = ({
|
||||
}
|
||||
|
||||
if (e.target.tagName.toLowerCase() !== 'a') {
|
||||
updateScrollPosition({ location, history });
|
||||
e.preventDefault();
|
||||
history.push(to);
|
||||
scrollTo();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let className = 'list__item';
|
||||
if (item.type) className += ` list__item--${item.type}`;
|
||||
|
||||
@ -6,7 +6,6 @@ import ErrorBoundary from './ErrorBoundary';
|
||||
const SmartListBatch = handleViewport(
|
||||
({
|
||||
items,
|
||||
isFirst,
|
||||
inViewport,
|
||||
forwardedRef,
|
||||
setItemHeight,
|
||||
@ -16,6 +15,8 @@ const SmartListBatch = handleViewport(
|
||||
batchIndex,
|
||||
chunkSize,
|
||||
className = '',
|
||||
isFirst,
|
||||
isLast,
|
||||
}) => {
|
||||
// Listen for changes to our height, and pass it up to our Grid. This is then used to build the
|
||||
// placeholder elements when out of viewport. We only care about the first item because this
|
||||
@ -34,8 +35,11 @@ const SmartListBatch = handleViewport(
|
||||
|
||||
return (
|
||||
<div className={`smart-list__batch ${className}`} ref={forwardedRef}>
|
||||
{inViewport || isFirst ? (
|
||||
<div className="smart-list__batch__inner" style={isFirst ? {} : { minHeight: itemHeight }}>
|
||||
{inViewport || isFirst || isLast ? (
|
||||
<div
|
||||
className="smart-list__batch__inner"
|
||||
style={isFirst || isLast ? {} : { minHeight: itemHeight }}
|
||||
>
|
||||
{
|
||||
items.map((item, index) => (
|
||||
<ItemComponent
|
||||
@ -67,11 +71,12 @@ const SmartList = memo(({
|
||||
if (!itemComponent) return null;
|
||||
|
||||
const [itemHeight, setItemHeight] = useState(initialHeight);
|
||||
const chunks = chunk(items, chunkSize);
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
{
|
||||
chunk(items, chunkSize).map((chunked, index) => (
|
||||
chunks.map((chunked, index) => (
|
||||
<SmartListBatch
|
||||
key={`smart-list__batch-${index}`} // Yeah yeah, I know; TODO
|
||||
className={className}
|
||||
@ -81,8 +86,9 @@ const SmartList = memo(({
|
||||
itemProps={itemProps}
|
||||
batchIndex={index}
|
||||
chunkSize={chunkSize}
|
||||
isFirst={index === 0}
|
||||
setItemHeight={setItemHeight}
|
||||
isFirst={index === 0}
|
||||
isLast={index === chunks.length - 1}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
||||
@ -540,47 +540,45 @@ const iconFromKeyword = (name) => {
|
||||
* @param smooth_scroll Boolean (optional)
|
||||
* */
|
||||
const scrollTo = function (target = null, smooth_scroll = false) {
|
||||
console.debug('scrollTo', { target, smooth_scroll })
|
||||
const main = document.getElementById('main');
|
||||
|
||||
// Remove our smooth-scroll class
|
||||
if (!smooth_scroll) {
|
||||
main.classList.remove('smooth-scroll');
|
||||
}
|
||||
|
||||
// Target is a number, so treat as pixel position
|
||||
if (target && Number.isInteger(target)) {
|
||||
if (typeof main.scrollTo === 'function') {
|
||||
main.scrollTop = target;
|
||||
}
|
||||
const performScroll = () => {
|
||||
if (!smooth_scroll) main.classList.remove('smooth-scroll');
|
||||
|
||||
// Target is a number, so treat as pixel position
|
||||
if (target && Number.isInteger(target)) {
|
||||
if (typeof main.scrollTo === 'function') {
|
||||
console.debug('Scrolling to', { main, target })
|
||||
main.scrollTo(0, target);
|
||||
}
|
||||
|
||||
// Target is a string representing a DOM element by class/id
|
||||
} else if (target) {
|
||||
let element = null;
|
||||
} else if (target) {
|
||||
let element = null;
|
||||
|
||||
if (target.charAt(0) == '#') {
|
||||
element = document.getElementById(target.substring(1));
|
||||
} else if (target.charAt(0) == '.') {
|
||||
element = document.getElementsByClassName(target.substring(1));
|
||||
if (element.length > 0) {
|
||||
element = element[0];
|
||||
if (target.charAt(0) === '#') {
|
||||
element = document.getElementById(target.substring(1));
|
||||
} else if (target.charAt(0) === '.') {
|
||||
element = document.getElementsByClassName(target.substring(1));
|
||||
if (element.length > 0) {
|
||||
element = element[0];
|
||||
}
|
||||
} else {
|
||||
console.error(`Invalid target type '${target}'. Must start with '#' or '.'.`);
|
||||
}
|
||||
|
||||
if (element && typeof element.scrollIntoView === 'function') {
|
||||
element.scrollIntoView();
|
||||
}
|
||||
} else {
|
||||
console.error(`Invalid target type '${target}'. Must start with '#' or '.'.`);
|
||||
main.scrollTop = 0;
|
||||
}
|
||||
|
||||
if (element && typeof element.scrollIntoView === 'function') {
|
||||
element.scrollIntoView();
|
||||
}
|
||||
} else {
|
||||
main.scrollTop = 0;
|
||||
}
|
||||
if (!smooth_scroll) main.classList.add('smooth-scroll');
|
||||
};
|
||||
|
||||
// Now reinstate smooth scroll
|
||||
if (!smooth_scroll) {
|
||||
main.classList.add('smooth-scroll');
|
||||
}
|
||||
// Give .main a moment to render it's contents
|
||||
setTimeout(performScroll, 1);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user