diff --git a/frontend/config/polyfills.js b/frontend/config/polyfills.js index 66dff0a8b1..54479964e5 100644 --- a/frontend/config/polyfills.js +++ b/frontend/config/polyfills.js @@ -1,5 +1,8 @@ 'use strict'; +require('react-app-polyfill/ie9'); +require('react-app-polyfill/stable'); + if (typeof Promise === 'undefined') { // Rejection tracking prevents a common issue where React gets into an // inconsistent state due to an error, but it gets swallowed by a Promise, diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 82c11c9f36..a7e71f55d5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1751,9 +1751,9 @@ }, "dependencies": { "core-js": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.5.tgz", - "integrity": "sha1-sU3ek2xkDAV5prUMq8wTLdYSfjs=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", "dev": true }, "regenerator-runtime": { @@ -4030,6 +4030,12 @@ "toggle-selection": "^1.0.3" } }, + "core-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.1.tgz", + "integrity": "sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew==", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -12002,6 +12008,52 @@ "prop-types": "^15.6.0" } }, + "react-app-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.1.tgz", + "integrity": "sha512-LbVpT1NdzTdDDs7xEZdebjDrqsvKi5UyVKUQqtTYYNyC1JJYVAwNQWe4ybWvoT2V2WW9PGVO2u5Y6aVj4ER/Ow==", + "dev": true, + "requires": { + "core-js": "3.0.1", + "object-assign": "4.1.1", + "promise": "8.0.2", + "raf": "3.4.1", + "regenerator-runtime": "0.13.2", + "whatwg-fetch": "3.0.0" + }, + "dependencies": { + "promise": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", + "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", + "dev": true, + "requires": { + "asap": "~2.0.6" + } + }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dev": true, + "requires": { + "performance-now": "^2.1.0" + } + }, + "regenerator-runtime": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", + "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==", + "dev": true + }, + "whatwg-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==", + "dev": true + } + } + }, "react-codemirror": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/react-codemirror/-/react-codemirror-1.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index f6ddba4716..51ded2514f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -120,6 +120,7 @@ "i18next": "^11.3.2", "i18next-browser-languagedetector": "^2.2.0", "i18next-xhr-backend": "^1.5.1", + "react-app-polyfill": "^1.0.1", "react-dev-utils": "^5.0.0", "react-i18next": "^7.6.1", "webpack": "3.8.1", diff --git a/frontend/src/components/context-menu/context-menu.js b/frontend/src/components/context-menu/context-menu.js index 119f39bcfb..fea7391fbe 100644 --- a/frontend/src/components/context-menu/context-menu.js +++ b/frontend/src/components/context-menu/context-menu.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import listener from './globalEventListener'; import { hideMenu } from './actions'; import { callIfExists } from './helpers'; +import { Utils } from '../../utils/utils'; const propTypes = { id: PropTypes.string.isRequired, @@ -192,7 +193,7 @@ class ContextMenu extends React.Component { onMenuItemClick = (event) => { event.stopPropagation(); - let operation = event.target.dataset.operation; + let operation = Utils.getEventData(event, 'operation'); let currentObject = this.state.currentObject; this.props.onMenuItemClick(operation, currentObject, event); } diff --git a/frontend/src/components/cur-dir-path/dir-path.js b/frontend/src/components/cur-dir-path/dir-path.js index 880bafce83..d201cbcc5c 100644 --- a/frontend/src/components/cur-dir-path/dir-path.js +++ b/frontend/src/components/cur-dir-path/dir-path.js @@ -4,6 +4,7 @@ import { Link } from '@reach/router'; import { UncontrolledTooltip } from 'reactstrap'; import { siteRoot, gettext } from '../../utils/constants'; import InternalLinkDialog from '../dialog/internal-link-dialog'; +import { Utils } from '../../utils/utils'; const propTypes = { repoName: PropTypes.string.isRequired, @@ -19,7 +20,7 @@ const propTypes = { class DirPath extends React.Component { onPathClick = (e) => { - let path = e.target.dataset.path; + let path = Utils.getEventData(e, 'path'); this.props.onPathClick(path); } diff --git a/frontend/src/components/dirent-list-view/dirent-list-item.js b/frontend/src/components/dirent-list-view/dirent-list-item.js index cc552ca846..59338ef9d8 100644 --- a/frontend/src/components/dirent-list-view/dirent-list-item.js +++ b/frontend/src/components/dirent-list-view/dirent-list-item.js @@ -346,32 +346,49 @@ class DirentListItem extends React.Component { } onItemDragStart = (e) => { + if (Utils.isIEBrower()) { + return false; + } let nodeRootPath = ''; nodeRootPath = this.props.path === '/' ? `${this.props.path}${this.props.dirent.name}` : `${this.props.path}/${this.props.dirent.name}`; let dragStartItemData = {nodeDirent: this.props.dirent, nodeParentPath: this.props.path, nodeRootPath: nodeRootPath}; dragStartItemData = JSON.stringify(dragStartItemData); e.dataTransfer.effectAllowed = 'move'; - e.dataTransfer.setDragImage(this.refs.drag_icon, 15, 15); + if (e.dataTransfer && e.dataTransfer.setDragImage) { + e.dataTransfer.setDragImage(this.refs.drag_icon, 15, 15); + } e.dataTransfer.setData('applicaiton/drag-item-info', dragStartItemData); } onItemDragEnter = () => { + if (Utils.isIEBrower()) { + return false; + } if (this.props.dirent.type === 'dir') { this.setState({isDropTipshow: true}); } } onItemDragOver = (e) => { + if (Utils.isIEBrower()) { + return false; + } e.preventDefault(); e.dataTransfer.dropEffect = 'move'; } onItemDragLeave = () => { + if (Utils.isIEBrower()) { + return false; + } this.setState({isDropTipshow: false}); } onItemDragDrop = (e) => { + if (Utils.isIEBrower()) { + return false; + } this.setState({isDropTipshow: false}); if (e.dataTransfer.files.length) { // uploaded files return; diff --git a/frontend/src/components/dirent-list-view/dirent-list-view.js b/frontend/src/components/dirent-list-view/dirent-list-view.js index 5c7336a79e..a032e38998 100644 --- a/frontend/src/components/dirent-list-view/dirent-list-view.js +++ b/frontend/src/components/dirent-list-view/dirent-list-view.js @@ -537,23 +537,35 @@ class DirentListView extends React.Component { } onTableDragEnter = (e) => { + if (Utils.isIEBrower()) { + return false; + } if (e.target.className === 'table-container ') { this.setState({isListDropTipShow: true}); } } onTableDragOver = (e) => { + if (Utils.isIEBrower()) { + return false; + } e.preventDefault(); e.dataTransfer.dropEffect = 'move'; } onTableDragLeave = (e) => { + if (Utils.isIEBrower()) { + return false; + } if (e.target.className === 'table-container table-drop-active') { this.setState({isListDropTipShow: false}); } } tableDrop = (e) => { + if (Utils.isIEBrower()) { + return false; + } e.persist(); this.setState({isListDropTipShow: false}); if (e.dataTransfer.files.length) { // uploaded files diff --git a/frontend/src/components/dropdown-menu/item-dropdown-menu.js b/frontend/src/components/dropdown-menu/item-dropdown-menu.js index ae229a0aab..f4ad32277f 100644 --- a/frontend/src/components/dropdown-menu/item-dropdown-menu.js +++ b/frontend/src/components/dropdown-menu/item-dropdown-menu.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import listener from '../context-menu/globalEventListener'; import { Dropdown, ButtonDropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap'; import { gettext } from '../../utils/constants'; +import { Utils } from '../../utils/utils'; const propTypes = { tagName: PropTypes.string, @@ -87,7 +88,7 @@ class ItemDropdownMenu extends React.Component { } onMenuItemClick = (event) => { - let operation = event.target.dataset.toggle; + let operation = Utils.getEventData(event, 'toggle'); let item = this.props.item; this.props.onMenuItemClick(operation, event, item); } diff --git a/frontend/src/components/file-uploader/file-uploader.js b/frontend/src/components/file-uploader/file-uploader.js index 46fb0282fa..26d4b21eee 100644 --- a/frontend/src/components/file-uploader/file-uploader.js +++ b/frontend/src/components/file-uploader/file-uploader.js @@ -414,19 +414,19 @@ class FileUploader extends React.Component { onFileUpload = () => { this.uploadInput.current.removeAttribute('webkitdirectory'); - this.uploadInput.current.click(); let repoID = this.props.repoID; seafileAPI.getUploadLink(repoID, this.props.path).then(res => { this.resumable.opts.target = res.data; + this.uploadInput.current.click(); }); } onFolderUpload = () => { this.uploadInput.current.setAttribute('webkitdirectory', 'webkitdirectory'); - this.uploadInput.current.click(); let repoID = this.props.repoID; seafileAPI.getUploadLink(repoID, this.props.path).then(res => { this.resumable.opts.target = res.data; + this.uploadInput.current.click(); }); } diff --git a/frontend/src/components/file-uploader/upload-list-item.js b/frontend/src/components/file-uploader/upload-list-item.js index 79513704a4..5bdf15e629 100644 --- a/frontend/src/components/file-uploader/upload-list-item.js +++ b/frontend/src/components/file-uploader/upload-list-item.js @@ -39,7 +39,7 @@ class UploadListItem extends React.Component {
{item.resumableFile.relativePath}
-
{error}
+
{this.formatFileSize(item.resumableFile.size)} diff --git a/frontend/src/components/toolbar/dir-operation-toolbar.js b/frontend/src/components/toolbar/dir-operation-toolbar.js index 25f39b6264..09a95dd5ed 100644 --- a/frontend/src/components/toolbar/dir-operation-toolbar.js +++ b/frontend/src/components/toolbar/dir-operation-toolbar.js @@ -55,9 +55,9 @@ class DirOperationToolbar extends React.Component { toggleOperationMenu = (e) => { e.nativeEvent.stopImmediatePropagation(); - let targetRect = e.target.getClientRects()[0]; - let left = targetRect.x; - let top = targetRect.y + targetRect.height; + let targetRect = e.target.getBoundingClientRect(); + let left = targetRect.left; + let top = targetRect.bottom; let style = {position: 'fixed', display: 'block', left: left, top: top}; this.setState({operationMenuStyle: style}); } diff --git a/frontend/src/components/tree-view/tree-view.js b/frontend/src/components/tree-view/tree-view.js index baf229969b..c3560ed5bc 100644 --- a/frontend/src/components/tree-view/tree-view.js +++ b/frontend/src/components/tree-view/tree-view.js @@ -4,6 +4,7 @@ import TextTranslation from '../../utils/text-translation'; import TreeNodeView from './tree-node-view'; import ContextMenu from '../context-menu/context-menu'; import { hideMenu, showMenu } from '../context-menu/actions'; +import { Utils } from '../../utils/utils'; const propTypes = { repoPermission: PropTypes.bool, @@ -36,6 +37,9 @@ class TreeView extends React.Component { } onNodeDragStart = (e, node) => { + if (Utils.isIEBrower()) { + return false; + } let dragStartNodeData = {nodeDirent: node.object, nodeParentPath: node.parentNode.path, nodeRootPath: node.path}; dragStartNodeData = JSON.stringify(dragStartNodeData); @@ -44,6 +48,9 @@ class TreeView extends React.Component { } onNodeDragEnter = (e, node) => { + if (Utils.isIEBrower()) { + return false; + } e.persist(); if (e.target.className === 'tree-view tree ') { this.setState({ @@ -53,11 +60,17 @@ class TreeView extends React.Component { } onNodeDragMove = (e) => { + if (Utils.isIEBrower()) { + return false; + } e.preventDefault(); e.dataTransfer.dropEffect = 'move'; } onNodeDragLeave = (e, node) => { + if (Utils.isIEBrower()) { + return false; + } if (e.target.className === 'tree-view tree tree-view-drop') { this.setState({ isTreeViewDropTipShow: false, @@ -66,6 +79,9 @@ class TreeView extends React.Component { } onNodeDrop = (e, node) => { + if (Utils.isIEBrower()) { + return false; + } if (e.dataTransfer.files.length) { // uploaded files return; } diff --git a/frontend/src/pages/my-libs/mylib-repo-menu.js b/frontend/src/pages/my-libs/mylib-repo-menu.js index edd955544b..007895ee55 100644 --- a/frontend/src/pages/my-libs/mylib-repo-menu.js +++ b/frontend/src/pages/my-libs/mylib-repo-menu.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap'; import { gettext, folderPermEnabled, enableRepoSnapshotLabel, enableResetEncryptedRepoPassword, isEmailConfigured } from '../../utils/constants'; +import { Utils } from '../../utils/utils'; const propTypes = { isPC: PropTypes.bool, @@ -21,7 +22,7 @@ class MylibRepoMenu extends React.Component { } onMenuItemClick = (e) => { - let operation = e.target.dataset.toggle; + let operation = Utils.getEventData(e, 'toggle'); this.props.onMenuItemClick(operation); } diff --git a/frontend/src/pages/wiki/main-panel.js b/frontend/src/pages/wiki/main-panel.js index e3fc05a324..ab9c2127c8 100644 --- a/frontend/src/pages/wiki/main-panel.js +++ b/frontend/src/pages/wiki/main-panel.js @@ -6,6 +6,7 @@ import CommonToolbar from '../../components/toolbar/common-toolbar'; import WikiMarkdownViewer from '../../components/wiki-markdown-viewer'; import WikiDirListView from '../../components/wiki-dir-list-view/wiki-dir-list-view'; import Loading from '../../components/loading'; +import { Utils } from '../../utils/utils'; const propTypes = { path: PropTypes.string.isRequired, @@ -37,7 +38,8 @@ class MainPanel extends Component { } onMainNavBarClick = (e) => { - this.props.onMainNavBarClick(e.target.dataset.path); + let path = Utils.getEventData(e, 'path'); + this.props.onMainNavBarClick(path); } renderNavPath = () => { diff --git a/frontend/src/utils/utils.js b/frontend/src/utils/utils.js index 48fbe6f576..9a80b81266 100644 --- a/frontend/src/utils/utils.js +++ b/frontend/src/utils/utils.js @@ -229,6 +229,13 @@ export const Utils = { navigator.userAgent.indexOf('Chrome') > -1; }, + isIEBrower: function() { // is ie <= ie11 not include Edge + var userAgent = navigator.userAgent; + var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; + var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1; + return isIE || isIE11; + }, + getDefaultLibIconUrl: function(isBig) { let size = Utils.isHiDPI() ? 48 : 24; size = isBig ? 256 : size; @@ -871,6 +878,14 @@ export const Utils = { password += possible.charAt(Math.floor(Math.random() * possible.length)); } return password; + }, + + getEventData: function(event, data) { + if (event.target.dataset) { + return event.target.dataset[data]; + } + return event.target.getAttribute('data-' + data); + } };